]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
USB: Move wusbcore and UWB to staging as it is obsolete
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 6 Aug 2019 10:15:09 +0000 (12:15 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 8 Aug 2019 05:52:01 +0000 (07:52 +0200)
The UWB and wusbcore code is long obsolete, so let us just move the code
out of the real part of the kernel and into the drivers/staging/
location with plans to remove it entirely in a few releases.

Link: https://lore.kernel.org/r/20190806101509.GA11280@kroah.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
169 files changed:
Documentation/usb/wusb-cbaf [deleted file]
Documentation/usb/wusb-design-overview.rst [deleted file]
MAINTAINERS
drivers/Kconfig
drivers/Makefile
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/uwb/Kconfig [new file with mode: 0644]
drivers/staging/uwb/Makefile [new file with mode: 0644]
drivers/staging/uwb/TODO [new file with mode: 0644]
drivers/staging/uwb/address.c [new file with mode: 0644]
drivers/staging/uwb/allocator.c [new file with mode: 0644]
drivers/staging/uwb/beacon.c [new file with mode: 0644]
drivers/staging/uwb/driver.c [new file with mode: 0644]
drivers/staging/uwb/drp-avail.c [new file with mode: 0644]
drivers/staging/uwb/drp-ie.c [new file with mode: 0644]
drivers/staging/uwb/drp.c [new file with mode: 0644]
drivers/staging/uwb/est.c [new file with mode: 0644]
drivers/staging/uwb/hwa-rc.c [new file with mode: 0644]
drivers/staging/uwb/i1480/Makefile [new file with mode: 0644]
drivers/staging/uwb/i1480/dfu/Makefile [new file with mode: 0644]
drivers/staging/uwb/i1480/dfu/dfu.c [new file with mode: 0644]
drivers/staging/uwb/i1480/dfu/i1480-dfu.h [new file with mode: 0644]
drivers/staging/uwb/i1480/dfu/mac.c [new file with mode: 0644]
drivers/staging/uwb/i1480/dfu/phy.c [new file with mode: 0644]
drivers/staging/uwb/i1480/dfu/usb.c [new file with mode: 0644]
drivers/staging/uwb/i1480/i1480-est.c [new file with mode: 0644]
drivers/staging/uwb/ie-rcv.c [new file with mode: 0644]
drivers/staging/uwb/ie.c [new file with mode: 0644]
drivers/staging/uwb/include/debug-cmd.h [new file with mode: 0644]
drivers/staging/uwb/include/spec.h [new file with mode: 0644]
drivers/staging/uwb/include/umc.h [new file with mode: 0644]
drivers/staging/uwb/include/whci.h [new file with mode: 0644]
drivers/staging/uwb/lc-dev.c [new file with mode: 0644]
drivers/staging/uwb/lc-rc.c [new file with mode: 0644]
drivers/staging/uwb/neh.c [new file with mode: 0644]
drivers/staging/uwb/pal.c [new file with mode: 0644]
drivers/staging/uwb/radio.c [new file with mode: 0644]
drivers/staging/uwb/reset.c [new file with mode: 0644]
drivers/staging/uwb/rsv.c [new file with mode: 0644]
drivers/staging/uwb/scan.c [new file with mode: 0644]
drivers/staging/uwb/umc-bus.c [new file with mode: 0644]
drivers/staging/uwb/umc-dev.c [new file with mode: 0644]
drivers/staging/uwb/umc-drv.c [new file with mode: 0644]
drivers/staging/uwb/uwb-debug.c [new file with mode: 0644]
drivers/staging/uwb/uwb-internal.h [new file with mode: 0644]
drivers/staging/uwb/uwb.h [new file with mode: 0644]
drivers/staging/uwb/uwbd.c [new file with mode: 0644]
drivers/staging/uwb/whc-rc.c [new file with mode: 0644]
drivers/staging/uwb/whci.c [new file with mode: 0644]
drivers/staging/wusbcore/Documentation/wusb-cbaf [new file with mode: 0644]
drivers/staging/wusbcore/Documentation/wusb-design-overview.rst [new file with mode: 0644]
drivers/staging/wusbcore/Kconfig [new file with mode: 0644]
drivers/staging/wusbcore/Makefile [new file with mode: 0644]
drivers/staging/wusbcore/TODO [new file with mode: 0644]
drivers/staging/wusbcore/cbaf.c [new file with mode: 0644]
drivers/staging/wusbcore/crypto.c [new file with mode: 0644]
drivers/staging/wusbcore/dev-sysfs.c [new file with mode: 0644]
drivers/staging/wusbcore/devconnect.c [new file with mode: 0644]
drivers/staging/wusbcore/host/Kconfig [new file with mode: 0644]
drivers/staging/wusbcore/host/Makefile [new file with mode: 0644]
drivers/staging/wusbcore/host/hwa-hc.c [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/Makefile [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/asl.c [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/debug.c [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/hcd.c [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/hw.c [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/init.c [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/int.c [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/pzl.c [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/qset.c [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/whcd.h [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/whci-hc.h [new file with mode: 0644]
drivers/staging/wusbcore/host/whci/wusb.c [new file with mode: 0644]
drivers/staging/wusbcore/include/association.h [new file with mode: 0644]
drivers/staging/wusbcore/include/wusb-wa.h [new file with mode: 0644]
drivers/staging/wusbcore/include/wusb.h [new file with mode: 0644]
drivers/staging/wusbcore/mmc.c [new file with mode: 0644]
drivers/staging/wusbcore/pal.c [new file with mode: 0644]
drivers/staging/wusbcore/reservation.c [new file with mode: 0644]
drivers/staging/wusbcore/rh.c [new file with mode: 0644]
drivers/staging/wusbcore/security.c [new file with mode: 0644]
drivers/staging/wusbcore/wa-hc.c [new file with mode: 0644]
drivers/staging/wusbcore/wa-hc.h [new file with mode: 0644]
drivers/staging/wusbcore/wa-nep.c [new file with mode: 0644]
drivers/staging/wusbcore/wa-rpipe.c [new file with mode: 0644]
drivers/staging/wusbcore/wa-xfer.c [new file with mode: 0644]
drivers/staging/wusbcore/wusbhc.c [new file with mode: 0644]
drivers/staging/wusbcore/wusbhc.h [new file with mode: 0644]
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/hwa-hc.c [deleted file]
drivers/usb/host/whci/Makefile [deleted file]
drivers/usb/host/whci/asl.c [deleted file]
drivers/usb/host/whci/debug.c [deleted file]
drivers/usb/host/whci/hcd.c [deleted file]
drivers/usb/host/whci/hw.c [deleted file]
drivers/usb/host/whci/init.c [deleted file]
drivers/usb/host/whci/int.c [deleted file]
drivers/usb/host/whci/pzl.c [deleted file]
drivers/usb/host/whci/qset.c [deleted file]
drivers/usb/host/whci/whcd.h [deleted file]
drivers/usb/host/whci/whci-hc.h [deleted file]
drivers/usb/host/whci/wusb.c [deleted file]
drivers/usb/wusbcore/Kconfig [deleted file]
drivers/usb/wusbcore/Makefile [deleted file]
drivers/usb/wusbcore/cbaf.c [deleted file]
drivers/usb/wusbcore/crypto.c [deleted file]
drivers/usb/wusbcore/dev-sysfs.c [deleted file]
drivers/usb/wusbcore/devconnect.c [deleted file]
drivers/usb/wusbcore/mmc.c [deleted file]
drivers/usb/wusbcore/pal.c [deleted file]
drivers/usb/wusbcore/reservation.c [deleted file]
drivers/usb/wusbcore/rh.c [deleted file]
drivers/usb/wusbcore/security.c [deleted file]
drivers/usb/wusbcore/wa-hc.c [deleted file]
drivers/usb/wusbcore/wa-hc.h [deleted file]
drivers/usb/wusbcore/wa-nep.c [deleted file]
drivers/usb/wusbcore/wa-rpipe.c [deleted file]
drivers/usb/wusbcore/wa-xfer.c [deleted file]
drivers/usb/wusbcore/wusbhc.c [deleted file]
drivers/usb/wusbcore/wusbhc.h [deleted file]
drivers/uwb/Kconfig [deleted file]
drivers/uwb/Makefile [deleted file]
drivers/uwb/address.c [deleted file]
drivers/uwb/allocator.c [deleted file]
drivers/uwb/beacon.c [deleted file]
drivers/uwb/driver.c [deleted file]
drivers/uwb/drp-avail.c [deleted file]
drivers/uwb/drp-ie.c [deleted file]
drivers/uwb/drp.c [deleted file]
drivers/uwb/est.c [deleted file]
drivers/uwb/hwa-rc.c [deleted file]
drivers/uwb/i1480/Makefile [deleted file]
drivers/uwb/i1480/dfu/Makefile [deleted file]
drivers/uwb/i1480/dfu/dfu.c [deleted file]
drivers/uwb/i1480/dfu/i1480-dfu.h [deleted file]
drivers/uwb/i1480/dfu/mac.c [deleted file]
drivers/uwb/i1480/dfu/phy.c [deleted file]
drivers/uwb/i1480/dfu/usb.c [deleted file]
drivers/uwb/i1480/i1480-est.c [deleted file]
drivers/uwb/ie-rcv.c [deleted file]
drivers/uwb/ie.c [deleted file]
drivers/uwb/lc-dev.c [deleted file]
drivers/uwb/lc-rc.c [deleted file]
drivers/uwb/neh.c [deleted file]
drivers/uwb/pal.c [deleted file]
drivers/uwb/radio.c [deleted file]
drivers/uwb/reset.c [deleted file]
drivers/uwb/rsv.c [deleted file]
drivers/uwb/scan.c [deleted file]
drivers/uwb/umc-bus.c [deleted file]
drivers/uwb/umc-dev.c [deleted file]
drivers/uwb/umc-drv.c [deleted file]
drivers/uwb/uwb-debug.c [deleted file]
drivers/uwb/uwb-internal.h [deleted file]
drivers/uwb/uwbd.c [deleted file]
drivers/uwb/whc-rc.c [deleted file]
drivers/uwb/whci.c [deleted file]
include/linux/usb/association.h [deleted file]
include/linux/usb/wusb-wa.h [deleted file]
include/linux/usb/wusb.h [deleted file]
include/linux/uwb.h [deleted file]
include/linux/uwb/debug-cmd.h [deleted file]
include/linux/uwb/spec.h [deleted file]
include/linux/uwb/umc.h [deleted file]
include/linux/uwb/whci.h [deleted file]

diff --git a/Documentation/usb/wusb-cbaf b/Documentation/usb/wusb-cbaf
deleted file mode 100644 (file)
index 8b3d43e..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-#! /bin/bash
-#
-
-set -e
-
-progname=$(basename $0)
-function help
-{
-    cat <<EOF
-Usage: $progname COMMAND DEVICEs [ARGS]
-
-Command for manipulating the pairing/authentication credentials of a
-Wireless USB device that supports wired-mode Cable-Based-Association.
-
-Works in conjunction with the wusb-cba.ko driver from http://linuxuwb.org.
-
-
-DEVICE
-
- sysfs path to the device to authenticate; for example, both this
- guys are the same:
-
- /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.4/1-4.4:1.1
- /sys/bus/usb/drivers/wusb-cbaf/1-4.4:1.1
-
-COMMAND/ARGS are
-
- start
-
-   Start a WUSB host controller (by setting up a CHID)
-
- set-chid DEVICE HOST-CHID HOST-BANDGROUP HOST-NAME
-
-   Sets host information in the device; after this you can call the
-   get-cdid to see how does this device report itself to us.
-
- get-cdid DEVICE
-
-   Get the device ID associated to the HOST-CHID we sent with
-   'set-chid'. We might not know about it.
-
- set-cc DEVICE
-
-   If we allow the device to connect, set a random new CDID and CK
-   (connection key). Device saves them for the next time it wants to
-   connect wireless. We save them for that next time also so we can
-   authenticate the device (when we see the CDID he uses to id
-   itself) and the CK to crypto talk to it.
-
-CHID is always 16 hex bytes in 'XX YY ZZ...' form
-BANDGROUP is almost always 0001
-
-Examples:
-
-  You can default most arguments to '' to get a sane value:
-
-  $ $progname set-chid '' '' '' "My host name"
-
-  A full sequence:
-
-  $ $progname set-chid '' '' '' "My host name"
-  $ $progname get-cdid ''
-  $ $progname set-cc ''
-
-EOF
-}
-
-
-# Defaults
-# FIXME: CHID should come from a database :), band group from the host
-host_CHID="00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff"
-host_band_group="0001"
-host_name=$(hostname)
-
-devs="$(echo /sys/bus/usb/drivers/wusb-cbaf/[0-9]*)"
-hdevs="$(for h in /sys/class/uwb_rc/*/wusbhc; do readlink -f $h; done)"
-
-result=0
-case $1 in
-    start)
-        for dev in ${2:-$hdevs}
-          do
-          echo $host_CHID > $dev/wusb_chid
-          echo I: started host $(basename $dev) >&2
-        done
-        ;;
-    stop)
-        for dev in ${2:-$hdevs}
-          do
-          echo 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 > $dev/wusb_chid
-          echo I: stopped host $(basename $dev) >&2
-        done
-        ;;
-    set-chid)
-        shift
-        for dev in ${2:-$devs}; do
-            echo "${4:-$host_name}" > $dev/wusb_host_name
-            echo "${3:-$host_band_group}" > $dev/wusb_host_band_groups
-            echo ${2:-$host_CHID} > $dev/wusb_chid
-        done
-        ;;
-    get-cdid)
-        for dev in ${2:-$devs}
-          do
-          cat $dev/wusb_cdid
-        done
-        ;;
-    set-cc)
-        for dev in ${2:-$devs}; do
-            shift
-            CDID="$(head --bytes=16 /dev/urandom  | od -tx1 -An)"
-            CK="$(head --bytes=16 /dev/urandom  | od -tx1 -An)"
-            echo "$CDID" > $dev/wusb_cdid
-            echo "$CK" > $dev/wusb_ck
-
-            echo I: CC set >&2
-            echo "CHID: $(cat $dev/wusb_chid)"
-            echo "CDID:$CDID"
-            echo "CK:  $CK"
-        done
-        ;;
-    help|h|--help|-h)
-        help
-        ;;
-    *)
-        echo "E: Unknown usage" 1>&2
-        help 1>&2
-        result=1
-esac
-exit $result
diff --git a/Documentation/usb/wusb-design-overview.rst b/Documentation/usb/wusb-design-overview.rst
deleted file mode 100644 (file)
index dc5e216..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-================================
-Linux UWB + Wireless USB + WiNET
-================================
-
-   Copyright (C) 2005-2006 Intel Corporation
-
-   Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
-
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License version
-   2 as published by the Free Software Foundation.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-
-Please visit http://bughost.org/thewiki/Design-overview.txt-1.8 for
-updated content.
-
-    * Design-overview.txt-1.8
-
-This code implements a Ultra Wide Band stack for Linux, as well as
-drivers for the USB based UWB radio controllers defined in the
-Wireless USB 1.0 specification (including Wireless USB host controller
-and an Intel WiNET controller).
-
-.. Contents
-   1. Introduction
-         1. HWA: Host Wire adapters, your Wireless USB dongle
-
-         2. DWA: Device Wired Adaptor, a Wireless USB hub for wired
-            devices
-         3. WHCI: Wireless Host Controller Interface, the PCI WUSB host
-            adapter
-   2. The UWB stack
-         1. Devices and hosts: the basic structure
-
-         2. Host Controller life cycle
-
-         3. On the air: beacons and enumerating the radio neighborhood
-
-         4. Device lists
-         5. Bandwidth allocation
-
-   3. Wireless USB Host Controller drivers
-
-   4. Glossary
-
-
-Introduction
-============
-
-UWB is a wide-band communication protocol that is to serve also as the
-low-level protocol for others (much like TCP sits on IP). Currently
-these others are Wireless USB and TCP/IP, but seems Bluetooth and
-Firewire/1394 are coming along.
-
-UWB uses a band from roughly 3 to 10 GHz, transmitting at a max of
-~-41dB (or 0.074 uW/MHz--geography specific data is still being
-negotiated w/ regulators, so watch for changes). That band is divided in
-a bunch of ~1.5 GHz wide channels (or band groups) composed of three
-subbands/subchannels (528 MHz each). Each channel is independent of each
-other, so you could consider them different "busses". Initially this
-driver considers them all a single one.
-
-Radio time is divided in 65536 us long /superframes/, each one divided
-in 256 256us long /MASs/ (Media Allocation Slots), which are the basic
-time/media allocation units for transferring data. At the beginning of
-each superframe there is a Beacon Period (BP), where every device
-transmit its beacon on a single MAS. The length of the BP depends on how
-many devices are present and the length of their beacons.
-
-Devices have a MAC (fixed, 48 bit address) and a device (changeable, 16
-bit address) and send periodic beacons to advertise themselves and pass
-info on what they are and do. They advertise their capabilities and a
-bunch of other stuff.
-
-The different logical parts of this driver are:
-
-    *
-
-      *UWB*: the Ultra-Wide-Band stack -- manages the radio and
-      associated spectrum to allow for devices sharing it. Allows to
-      control bandwidth assignment, beaconing, scanning, etc
-
-    *
-
-      *WUSB*: the layer that sits on top of UWB to provide Wireless USB.
-      The Wireless USB spec defines means to control a UWB radio and to
-      do the actual WUSB.
-
-
-HWA: Host Wire adapters, your Wireless USB dongle
--------------------------------------------------
-
-WUSB also defines a device called a Host Wire Adaptor (HWA), which in
-mere terms is a USB dongle that enables your PC to have UWB and Wireless
-USB. The Wireless USB Host Controller in a HWA looks to the host like a
-[Wireless] USB controller connected via USB (!)
-
-The HWA itself is broken in two or three main interfaces:
-
-    *
-
-      *RC*: Radio control -- this implements an interface to the
-      Ultra-Wide-Band radio controller. The driver for this implements a
-      USB-based UWB Radio Controller to the UWB stack.
-
-    *
-
-      *HC*: the wireless USB host controller. It looks like a USB host
-      whose root port is the radio and the WUSB devices connect to it.
-      To the system it looks like a separate USB host. The driver (will)
-      implement a USB host controller (similar to UHCI, OHCI or EHCI)
-      for which the root hub is the radio...To reiterate: it is a USB
-      controller that is connected via USB instead of PCI.
-
-    *
-
-      *WINET*: some HW provide a WiNET interface (IP over UWB). This
-      package provides a driver for it (it looks like a network
-      interface, winetX). The driver detects when there is a link up for
-      their type and kick into gear.
-
-
-DWA: Device Wired Adaptor, a Wireless USB hub for wired devices
----------------------------------------------------------------
-
-These are the complement to HWAs. They are a USB host for connecting
-wired devices, but it is connected to your PC connected via Wireless
-USB. To the system it looks like yet another USB host. To the untrained
-eye, it looks like a hub that connects upstream wirelessly.
-
-We still offer no support for this; however, it should share a lot of
-code with the HWA-RC driver; there is a bunch of factorization work that
-has been done to support that in upcoming releases.
-
-
-WHCI: Wireless Host Controller Interface, the PCI WUSB host adapter
--------------------------------------------------------------------
-
-This is your usual PCI device that implements WHCI. Similar in concept
-to EHCI, it allows your wireless USB devices (including DWAs) to connect
-to your host via a PCI interface. As in the case of the HWA, it has a
-Radio Control interface and the WUSB Host Controller interface per se.
-
-There is still no driver support for this, but will be in upcoming
-releases.
-
-
-The UWB stack
-=============
-
-The main mission of the UWB stack is to keep a tally of which devices
-are in radio proximity to allow drivers to connect to them. As well, it
-provides an API for controlling the local radio controllers (RCs from
-now on), such as to start/stop beaconing, scan, allocate bandwidth, etc.
-
-
-Devices and hosts: the basic structure
---------------------------------------
-
-The main building block here is the UWB device (struct uwb_dev). For
-each device that pops up in radio presence (ie: the UWB host receives a
-beacon from it) you get a struct uwb_dev that will show up in
-/sys/bus/uwb/devices.
-
-For each RC that is detected, a new struct uwb_rc and struct uwb_dev are
-created. An entry is also created in /sys/class/uwb_rc for each RC.
-
-Each RC driver is implemented by a separate driver that plugs into the
-interface that the UWB stack provides through a struct uwb_rc_ops. The
-spec creators have been nice enough to make the message format the same
-for HWA and WHCI RCs, so the driver is really a very thin transport that
-moves the requests from the UWB API to the device [/uwb_rc_ops->cmd()/]
-and sends the replies and notifications back to the API
-[/uwb_rc_neh_grok()/]. Notifications are handled to the UWB daemon, that
-is chartered, among other things, to keep the tab of how the UWB radio
-neighborhood looks, creating and destroying devices as they show up or
-disappear.
-
-Command execution is very simple: a command block is sent and a event
-block or reply is expected back. For sending/receiving command/events, a
-handle called /neh/ (Notification/Event Handle) is opened with
-/uwb_rc_neh_open()/.
-
-The HWA-RC (USB dongle) driver (drivers/uwb/hwa-rc.c) does this job for
-the USB connected HWA. Eventually, drivers/whci-rc.c will do the same
-for the PCI connected WHCI controller.
-
-
-Host Controller life cycle
---------------------------
-
-So let's say we connect a dongle to the system: it is detected and
-firmware uploaded if needed [for Intel's i1480
-/drivers/uwb/ptc/usb.c:ptc_usb_probe()/] and then it is reenumerated.
-Now we have a real HWA device connected and
-/drivers/uwb/hwa-rc.c:hwarc_probe()/ picks it up, that will set up the
-Wire-Adaptor environment and then suck it into the UWB stack's vision of
-the world [/drivers/uwb/lc-rc.c:uwb_rc_add()/].
-
-    *
-
-      [*] The stack should put a new RC to scan for devices
-      [/uwb_rc_scan()/] so it finds what's available around and tries to
-      connect to them, but this is policy stuff and should be driven
-      from user space. As of now, the operator is expected to do it
-      manually; see the release notes for documentation on the procedure.
-
-When a dongle is disconnected, /drivers/uwb/hwa-rc.c:hwarc_disconnect()/
-takes time of tearing everything down safely (or not...).
-
-
-On the air: beacons and enumerating the radio neighborhood
-----------------------------------------------------------
-
-So assuming we have devices and we have agreed for a channel to connect
-on (let's say 9), we put the new RC to beacon:
-
-    *
-
-            $ echo 9 0 > /sys/class/uwb_rc/uwb0/beacon
-
-Now it is visible. If there were other devices in the same radio channel
-and beacon group (that's what the zero is for), the dongle's radio
-control interface will send beacon notifications on its
-notification/event endpoint (NEEP). The beacon notifications are part of
-the event stream that is funneled into the API with
-/drivers/uwb/neh.c:uwb_rc_neh_grok()/ and delivered to the UWBD, the UWB
-daemon through a notification list.
-
-UWBD wakes up and scans the event list; finds a beacon and adds it to
-the BEACON CACHE (/uwb_beca/). If he receives a number of beacons from
-the same device, he considers it to be 'onair' and creates a new device
-[/drivers/uwb/lc-dev.c:uwbd_dev_onair()/]. Similarly, when no beacons
-are received in some time, the device is considered gone and wiped out
-[uwbd calls periodically /uwb/beacon.c:uwb_beca_purge()/ that will purge
-the beacon cache of dead devices].
-
-
-Device lists
-------------
-
-All UWB devices are kept in the list of the struct bus_type uwb_bus_type.
-
-
-Bandwidth allocation
---------------------
-
-The UWB stack maintains a local copy of DRP availability through
-processing of incoming *DRP Availability Change* notifications. This
-local copy is currently used to present the current bandwidth
-availability to the user through the sysfs file
-/sys/class/uwb_rc/uwbx/bw_avail. In the future the bandwidth
-availability information will be used by the bandwidth reservation
-routines.
-
-The bandwidth reservation routines are in progress and are thus not
-present in the current release. When completed they will enable a user
-to initiate DRP reservation requests through interaction with sysfs. DRP
-reservation requests from remote UWB devices will also be handled. The
-bandwidth management done by the UWB stack will include callbacks to the
-higher layers will enable the higher layers to use the reservations upon
-completion. [Note: The bandwidth reservation work is in progress and
-subject to change.]
-
-
-Wireless USB Host Controller drivers
-====================================
-
-*WARNING* This section needs a lot of work!
-
-As explained above, there are three different types of HCs in the WUSB
-world: HWA-HC, DWA-HC and WHCI-HC.
-
-HWA-HC and DWA-HC share that they are Wire-Adapters (USB or WUSB
-connected controllers), and their transfer management system is almost
-identical. So is their notification delivery system.
-
-HWA-HC and WHCI-HC share that they are both WUSB host controllers, so
-they have to deal with WUSB device life cycle and maintenance, wireless
-root-hub
-
-HWA exposes a Host Controller interface (HWA-HC 0xe0/02/02). This has
-three endpoints (Notifications, Data Transfer In and Data Transfer
-Out--known as NEP, DTI and DTO in the code).
-
-We reserve UWB bandwidth for our Wireless USB Cluster, create a Cluster
-ID and tell the HC to use all that. Then we start it. This means the HC
-starts sending MMCs.
-
-    *
-
-      The MMCs are blocks of data defined somewhere in the WUSB1.0 spec
-      that define a stream in the UWB channel time allocated for sending
-      WUSB IEs (host to device commands/notifications) and Device
-      Notifications (device initiated to host). Each host defines a
-      unique Wireless USB cluster through MMCs. Devices can connect to a
-      single cluster at the time. The IEs are Information Elements, and
-      among them are the bandwidth allocations that tell each device
-      when can they transmit or receive.
-
-Now it all depends on external stimuli.
-
-New device connection
----------------------
-
-A new device pops up, it scans the radio looking for MMCs that give out
-the existence of Wireless USB channels. Once one (or more) are found,
-selects which one to connect to. Sends a /DN_Connect/ (device
-notification connect) during the DNTS (Device Notification Time
-Slot--announced in the MMCs
-
-HC picks the /DN_Connect/ out (nep module sends to notif.c for delivery
-into /devconnect/). This process starts the authentication process for
-the device. First we allocate a /fake port/ and assign an
-unauthenticated address (128 to 255--what we really do is
-0x80 | fake_port_idx). We fiddle with the fake port status and /hub_wq/
-sees a new connection, so he moves on to enable the fake port with a reset.
-
-So now we are in the reset path -- we know we have a non-yet enumerated
-device with an unauthorized address; we ask user space to authenticate
-(FIXME: not yet done, similar to bluetooth pairing), then we do the key
-exchange (FIXME: not yet done) and issue a /set address 0/ to bring the
-device to the default state. Device is authenticated.
-
-From here, the USB stack takes control through the usb_hcd ops. hub_wq
-has seen the port status changes, as we have been toggling them. It will
-start enumerating and doing transfers through usb_hcd->urb_enqueue() to
-read descriptors and move our data.
-
-Device life cycle and keep alives
----------------------------------
-
-Every time there is a successful transfer to/from a device, we update a
-per-device activity timestamp. If not, every now and then we check and
-if the activity timestamp gets old, we ping the device by sending it a
-Keep Alive IE; it responds with a /DN_Alive/ pong during the DNTS (this
-arrives to us as a notification through
-devconnect.c:wusb_handle_dn_alive(). If a device times out, we
-disconnect it from the system (cleaning up internal information and
-toggling the bits in the fake hub port, which kicks hub_wq into removing
-the rest of the stuff).
-
-This is done through devconnect:__wusb_check_devs(), which will scan the
-device list looking for whom needs refreshing.
-
-If the device wants to disconnect, it will either die (ugly) or send a
-/DN_Disconnect/ that will prompt a disconnection from the system.
-
-Sending and receiving data
---------------------------
-
-Data is sent and received through /Remote Pipes/ (rpipes). An rpipe is
-/aimed/ at an endpoint in a WUSB device. This is the same for HWAs and
-DWAs.
-
-Each HC has a number of rpipes and buffers that can be assigned to them;
-when doing a data transfer (xfer), first the rpipe has to be aimed and
-prepared (buffers assigned), then we can start queueing requests for
-data in or out.
-
-Data buffers have to be segmented out before sending--so we send first a
-header (segment request) and then if there is any data, a data buffer
-immediately after to the DTI interface (yep, even the request). If our
-buffer is bigger than the max segment size, then we just do multiple
-requests.
-
-[This sucks, because doing USB scatter gatter in Linux is resource
-intensive, if any...not that the current approach is not. It just has to
-be cleaned up a lot :)].
-
-If reading, we don't send data buffers, just the segment headers saying
-we want to read segments.
-
-When the xfer is executed, we receive a notification that says data is
-ready in the DTI endpoint (handled through
-xfer.c:wa_handle_notif_xfer()). In there we read from the DTI endpoint a
-descriptor that gives us the status of the transfer, its identification
-(given when we issued it) and the segment number. If it was a data read,
-we issue another URB to read into the destination buffer the chunk of
-data coming out of the remote endpoint. Done, wait for the next guy. The
-callbacks for the URBs issued from here are the ones that will declare
-the xfer complete at some point and call its callback.
-
-Seems simple, but the implementation is not trivial.
-
-    *
-
-      *WARNING* Old!!
-
-The main xfer descriptor, wa_xfer (equivalent to a URB) contains an
-array of segments, tallys on segments and buffers and callback
-information. Buried in there is a lot of URBs for executing the segments
-and buffer transfers.
-
-For OUT xfers, there is an array of segments, one URB for each, another
-one of buffer URB. When submitting, we submit URBs for segment request
-1, buffer 1, segment 2, buffer 2...etc. Then we wait on the DTI for xfer
-result data; when all the segments are complete, we call the callback to
-finalize the transfer.
-
-For IN xfers, we only issue URBs for the segments we want to read and
-then wait for the xfer result data.
-
-URB mapping into xfers
-^^^^^^^^^^^^^^^^^^^^^^
-
-This is done by hwahc_op_urb_[en|de]queue(). In enqueue() we aim an
-rpipe to the endpoint where we have to transmit, create a transfer
-context (wa_xfer) and submit it. When the xfer is done, our callback is
-called and we assign the status bits and release the xfer resources.
-
-In dequeue() we are basically cancelling/aborting the transfer. We issue
-a xfer abort request to the HC, cancel all the URBs we had submitted
-and not yet done and when all that is done, the xfer callback will be
-called--this will call the URB callback.
-
-
-Glossary
-========
-
-*DWA* -- Device Wire Adapter
-
-USB host, wired for downstream devices, upstream connects wirelessly
-with Wireless USB.
-
-*EVENT* -- Response to a command on the NEEP
-
-*HWA* -- Host Wire Adapter / USB dongle for UWB and Wireless USB
-
-*NEH* -- Notification/Event Handle
-
-Handle/file descriptor for receiving notifications or events. The WA
-code requires you to get one of this to listen for notifications or
-events on the NEEP.
-
-*NEEP* -- Notification/Event EndPoint
-
-Stuff related to the management of the first endpoint of a HWA USB
-dongle that is used to deliver an stream of events and notifications to
-the host.
-
-*NOTIFICATION* -- Message coming in the NEEP as response to something.
-
-*RC* -- Radio Control
-
-Design-overview.txt-1.8 (last edited 2006-11-04 12:22:24 by
-InakyPerezGonzalez)
index 6426db5198f0537746c22d10f95ce4a5004fdde3..f4463fb482490dd563469f6b080e3324dfeece57 100644 (file)
@@ -3800,14 +3800,9 @@ F:       scripts/sign-file.c
 F:     scripts/extract-cert.c
 
 CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
-L:     linux-usb@vger.kernel.org
+L:     devel@driverdev.osuosl.org
 S:     Orphan
-F:     Documentation/usb/wusb-design-overview.rst
-F:     Documentation/usb/wusb-cbaf
-F:     drivers/usb/host/hwa-hc.c
-F:     drivers/usb/host/whci/
-F:     drivers/usb/wusbcore/
-F:     include/linux/usb/wusb*
+F:     drivers/staging/wbusbcore/
 
 CFAG12864B LCD DRIVER
 M:     Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
@@ -16447,11 +16442,9 @@ F:     drivers/usb/common/ulpi.c
 F:     include/linux/ulpi/
 
 ULTRA-WIDEBAND (UWB) SUBSYSTEM:
-L:     linux-usb@vger.kernel.org
+L:     devel@driverdev.osuosl.org
 S:     Orphan
-F:     drivers/uwb/
-F:     include/linux/uwb.h
-F:     include/linux/uwb/
+F:     drivers/staging/uwb/
 
 UNICODE SUBSYSTEM:
 M:     Gabriel Krisman Bertazi <krisman@collabora.com>
index 61cf4ea2c229b3c03e2fcb5a890def6a15642d31..e8852c09184b595887c787b0fae58cde7b82e213 100644 (file)
@@ -108,8 +108,6 @@ source "drivers/hid/Kconfig"
 
 source "drivers/usb/Kconfig"
 
-source "drivers/uwb/Kconfig"
-
 source "drivers/mmc/Kconfig"
 
 source "drivers/memstick/Kconfig"
index 6d37564e783cb2d27f86a5c38b00891dee611cee..cf046e9bd88ca06dde860b730b6cad5ff7fde9ba 100644 (file)
@@ -100,7 +100,6 @@ obj-$(CONFIG_ZORRO)         += zorro/
 obj-$(CONFIG_ATA_OVER_ETH)     += block/aoe/
 obj-$(CONFIG_PARIDE)           += block/paride/
 obj-$(CONFIG_TC)               += tc/
-obj-$(CONFIG_UWB)              += uwb/
 obj-$(CONFIG_USB_PHY)          += usb/
 obj-$(CONFIG_USB)              += usb/
 obj-$(CONFIG_USB_SUPPORT)      += usb/
index 7c96a01eef6c714f390816c18d6916aaaddaa721..cf419d9c942d013ae4f19c44a2bbeac02609544c 100644 (file)
@@ -120,4 +120,7 @@ source "drivers/staging/kpc2000/Kconfig"
 
 source "drivers/staging/isdn/Kconfig"
 
+source "drivers/staging/wusbcore/Kconfig"
+source "drivers/staging/uwb/Kconfig"
+
 endif # STAGING
index fcaac9693b8312d45d21667660c7f958a5c2a734..38179bc842a8518b28672f5575161116ffa413c4 100644 (file)
@@ -50,3 +50,5 @@ obj-$(CONFIG_EROFS_FS)                += erofs/
 obj-$(CONFIG_FIELDBUS_DEV)     += fieldbus/
 obj-$(CONFIG_KPC2000)          += kpc2000/
 obj-$(CONFIG_ISDN_CAPI)                += isdn/
+obj-$(CONFIG_UWB)              += uwb/
+obj-$(CONFIG_USB_WUSB)         += wusbcore/
diff --git a/drivers/staging/uwb/Kconfig b/drivers/staging/uwb/Kconfig
new file mode 100644 (file)
index 0000000..259e053
--- /dev/null
@@ -0,0 +1,72 @@
+# 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
diff --git a/drivers/staging/uwb/Makefile b/drivers/staging/uwb/Makefile
new file mode 100644 (file)
index 0000000..32f4de7
--- /dev/null
@@ -0,0 +1,32 @@
+# 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
diff --git a/drivers/staging/uwb/TODO b/drivers/staging/uwb/TODO
new file mode 100644 (file)
index 0000000..abae570
--- /dev/null
@@ -0,0 +1,8 @@
+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>
diff --git a/drivers/staging/uwb/address.c b/drivers/staging/uwb/address.c
new file mode 100644 (file)
index 0000000..857d5cd
--- /dev/null
@@ -0,0 +1,352 @@
+// 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);
diff --git a/drivers/staging/uwb/allocator.c b/drivers/staging/uwb/allocator.c
new file mode 100644 (file)
index 0000000..1f429fb
--- /dev/null
@@ -0,0 +1,374 @@
+// 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;
+}
diff --git a/drivers/staging/uwb/beacon.c b/drivers/staging/uwb/beacon.c
new file mode 100644 (file)
index 0000000..c483c19
--- /dev/null
@@ -0,0 +1,595 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Beacon management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ */
+#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/slab.h>
+
+#include "uwb-internal.h"
+
+/* Start Beaconing command structure */
+struct uwb_rc_cmd_start_beacon {
+       struct uwb_rccb rccb;
+       __le16 wBPSTOffset;
+       u8 bChannelNumber;
+} __attribute__((packed));
+
+
+static int uwb_rc_start_beacon(struct uwb_rc *rc, u16 bpst_offset, u8 channel)
+{
+       int result;
+       struct uwb_rc_cmd_start_beacon *cmd;
+       struct uwb_rc_evt_confirm reply;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+       cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+       cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_START_BEACON);
+       cmd->wBPSTOffset = cpu_to_le16(bpst_offset);
+       cmd->bChannelNumber = channel;
+       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+       reply.rceb.wEvent = UWB_RC_CMD_START_BEACON;
+       result = uwb_rc_cmd(rc, "START-BEACON", &cmd->rccb, sizeof(*cmd),
+                           &reply.rceb, sizeof(reply));
+       if (result < 0)
+               goto error_cmd;
+       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+               dev_err(&rc->uwb_dev.dev,
+                       "START-BEACON: command execution failed: %s (%d)\n",
+                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+               result = -EIO;
+       }
+error_cmd:
+       kfree(cmd);
+       return result;
+}
+
+static int uwb_rc_stop_beacon(struct uwb_rc *rc)
+{
+       int result;
+       struct uwb_rccb *cmd;
+       struct uwb_rc_evt_confirm reply;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+       cmd->bCommandType = UWB_RC_CET_GENERAL;
+       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_STOP_BEACON);
+       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+       reply.rceb.wEvent = UWB_RC_CMD_STOP_BEACON;
+       result = uwb_rc_cmd(rc, "STOP-BEACON", cmd, sizeof(*cmd),
+                           &reply.rceb, sizeof(reply));
+       if (result < 0)
+               goto error_cmd;
+       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+               dev_err(&rc->uwb_dev.dev,
+                       "STOP-BEACON: command execution failed: %s (%d)\n",
+                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+               result = -EIO;
+       }
+error_cmd:
+       kfree(cmd);
+       return result;
+}
+
+/*
+ * Start/stop beacons
+ *
+ * @rc:          UWB Radio Controller to operate on
+ * @channel:     UWB channel on which to beacon (WUSB[table
+ *               5-12]). If -1, stop beaconing.
+ * @bpst_offset: Beacon Period Start Time offset; FIXME-do zero
+ *
+ * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
+ * of a SET IE command after the device sent the first beacon that includes
+ * the IEs specified in the SET IE command. So, after we start beaconing we
+ * check if there is anything in the IE cache and call the SET IE command
+ * if needed.
+ */
+int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset)
+{
+       int result;
+       struct device *dev = &rc->uwb_dev.dev;
+
+       dev_dbg(dev, "%s: channel = %d\n", __func__, channel);
+       if (channel < 0)
+               channel = -1;
+       if (channel == -1)
+               result = uwb_rc_stop_beacon(rc);
+       else {
+               /* channel >= 0...dah */
+               result = uwb_rc_start_beacon(rc, bpst_offset, channel);
+               if (result < 0) {
+                       dev_err(dev, "Cannot start beaconing: %d\n", result);
+                       return result;
+               }
+               if (le16_to_cpu(rc->ies->wIELength) > 0) {
+                       result = uwb_rc_set_ie(rc, rc->ies);
+                       if (result < 0) {
+                               dev_err(dev, "Cannot set new IE on device: "
+                                       "%d\n", result);
+                               result = uwb_rc_stop_beacon(rc);
+                               channel = -1;
+                               bpst_offset = 0;
+                       }
+               }
+       }
+
+       if (result >= 0)
+               rc->beaconing = channel;
+       return result;
+}
+
+/*
+ * Beacon cache
+ *
+ * The purpose of this is to speed up the lookup of becon information
+ * when a new beacon arrives. The UWB Daemon uses it also to keep a
+ * tab of which devices are in radio distance and which not. When a
+ * device's beacon stays present for more than a certain amount of
+ * time, it is considered a new, usable device. When a beacon ceases
+ * to be received for a certain amount of time, it is considered that
+ * the device is gone.
+ *
+ * FIXME: use an allocator for the entries
+ * FIXME: use something faster for search than a list
+ */
+
+void uwb_bce_kfree(struct kref *_bce)
+{
+       struct uwb_beca_e *bce = container_of(_bce, struct uwb_beca_e, refcnt);
+
+       kfree(bce->be);
+       kfree(bce);
+}
+
+
+/* Find a beacon by dev addr in the cache */
+static
+struct uwb_beca_e *__uwb_beca_find_bydev(struct uwb_rc *rc,
+                                        const struct uwb_dev_addr *dev_addr)
+{
+       struct uwb_beca_e *bce, *next;
+       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
+               if (!memcmp(&bce->dev_addr, dev_addr, sizeof(bce->dev_addr)))
+                       goto out;
+       }
+       bce = NULL;
+out:
+       return bce;
+}
+
+/* Find a beacon by dev addr in the cache */
+static
+struct uwb_beca_e *__uwb_beca_find_bymac(struct uwb_rc *rc,
+                                        const struct uwb_mac_addr *mac_addr)
+{
+       struct uwb_beca_e *bce, *next;
+       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
+               if (!memcmp(bce->mac_addr, mac_addr->data,
+                           sizeof(struct uwb_mac_addr)))
+                       goto out;
+       }
+       bce = NULL;
+out:
+       return bce;
+}
+
+/**
+ * uwb_dev_get_by_devaddr - get a UWB device with a specific DevAddr
+ * @rc:      the radio controller that saw the device
+ * @devaddr: DevAddr of the UWB device to find
+ *
+ * There may be more than one matching device (in the case of a
+ * DevAddr conflict), but only the first one is returned.
+ */
+struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
+                                      const struct uwb_dev_addr *devaddr)
+{
+       struct uwb_dev *found = NULL;
+       struct uwb_beca_e *bce;
+
+       mutex_lock(&rc->uwb_beca.mutex);
+       bce = __uwb_beca_find_bydev(rc, devaddr);
+       if (bce)
+               found = uwb_dev_try_get(rc, bce->uwb_dev);
+       mutex_unlock(&rc->uwb_beca.mutex);
+
+       return found;
+}
+
+/**
+ * uwb_dev_get_by_macaddr - get a UWB device with a specific EUI-48
+ * @rc:      the radio controller that saw the device
+ * @devaddr: EUI-48 of the UWB device to find
+ */
+struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
+                                      const struct uwb_mac_addr *macaddr)
+{
+       struct uwb_dev *found = NULL;
+       struct uwb_beca_e *bce;
+
+       mutex_lock(&rc->uwb_beca.mutex);
+       bce = __uwb_beca_find_bymac(rc, macaddr);
+       if (bce)
+               found = uwb_dev_try_get(rc, bce->uwb_dev);
+       mutex_unlock(&rc->uwb_beca.mutex);
+
+       return found;
+}
+
+/* Initialize a beacon cache entry */
+static void uwb_beca_e_init(struct uwb_beca_e *bce)
+{
+       mutex_init(&bce->mutex);
+       kref_init(&bce->refcnt);
+       stats_init(&bce->lqe_stats);
+       stats_init(&bce->rssi_stats);
+}
+
+/*
+ * Add a beacon to the cache
+ *
+ * @be:         Beacon event information
+ * @bf:         Beacon frame (part of b, really)
+ * @ts_jiffies: Timestamp (in jiffies) when the beacon was received
+ */
+static
+struct uwb_beca_e *__uwb_beca_add(struct uwb_rc *rc,
+                                 struct uwb_rc_evt_beacon *be,
+                                 struct uwb_beacon_frame *bf,
+                                 unsigned long ts_jiffies)
+{
+       struct uwb_beca_e *bce;
+
+       bce = kzalloc(sizeof(*bce), GFP_KERNEL);
+       if (bce == NULL)
+               return NULL;
+       uwb_beca_e_init(bce);
+       bce->ts_jiffies = ts_jiffies;
+       bce->uwb_dev = NULL;
+       list_add(&bce->node, &rc->uwb_beca.list);
+       return bce;
+}
+
+/*
+ * Wipe out beacon entries that became stale
+ *
+ * Remove associated devicest too.
+ */
+void uwb_beca_purge(struct uwb_rc *rc)
+{
+       struct uwb_beca_e *bce, *next;
+       unsigned long expires;
+
+       mutex_lock(&rc->uwb_beca.mutex);
+       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
+               expires = bce->ts_jiffies + msecs_to_jiffies(beacon_timeout_ms);
+               if (time_after(jiffies, expires)) {
+                       uwbd_dev_offair(bce);
+               }
+       }
+       mutex_unlock(&rc->uwb_beca.mutex);
+}
+
+/* Clean up the whole beacon cache. Called on shutdown */
+void uwb_beca_release(struct uwb_rc *rc)
+{
+       struct uwb_beca_e *bce, *next;
+
+       mutex_lock(&rc->uwb_beca.mutex);
+       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
+               list_del(&bce->node);
+               uwb_bce_put(bce);
+       }
+       mutex_unlock(&rc->uwb_beca.mutex);
+}
+
+static void uwb_beacon_print(struct uwb_rc *rc, struct uwb_rc_evt_beacon *be,
+                            struct uwb_beacon_frame *bf)
+{
+       char macbuf[UWB_ADDR_STRSIZE];
+       char devbuf[UWB_ADDR_STRSIZE];
+       char dstbuf[UWB_ADDR_STRSIZE];
+
+       uwb_mac_addr_print(macbuf, sizeof(macbuf), &bf->Device_Identifier);
+       uwb_dev_addr_print(devbuf, sizeof(devbuf), &bf->hdr.SrcAddr);
+       uwb_dev_addr_print(dstbuf, sizeof(dstbuf), &bf->hdr.DestAddr);
+       dev_info(&rc->uwb_dev.dev,
+                "BEACON from %s to %s (ch%u offset %u slot %u MAC %s)\n",
+                devbuf, dstbuf, be->bChannelNumber, be->wBPSTOffset,
+                bf->Beacon_Slot_Number, macbuf);
+}
+
+/*
+ * @bce: beacon cache entry, referenced
+ */
+ssize_t uwb_bce_print_IEs(struct uwb_dev *uwb_dev, struct uwb_beca_e *bce,
+                         char *buf, size_t size)
+{
+       ssize_t result = 0;
+       struct uwb_rc_evt_beacon *be;
+       struct uwb_beacon_frame *bf;
+       int ies_len;
+       struct uwb_ie_hdr *ies;
+
+       mutex_lock(&bce->mutex);
+
+       be = bce->be;
+       if (be) {
+               bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
+               ies_len = be->wBeaconInfoLength - sizeof(struct uwb_beacon_frame);
+               ies = (struct uwb_ie_hdr *)bf->IEData;
+
+               result = uwb_ie_dump_hex(ies, ies_len, buf, size);
+       }
+
+       mutex_unlock(&bce->mutex);
+
+       return result;
+}
+
+/*
+ * Verify that the beacon event, frame and IEs are ok
+ */
+static int uwb_verify_beacon(struct uwb_rc *rc, struct uwb_event *evt,
+                            struct uwb_rc_evt_beacon *be)
+{
+       int result = -EINVAL;
+       struct uwb_beacon_frame *bf;
+       struct device *dev = &rc->uwb_dev.dev;
+
+       /* Is there enough data to decode a beacon frame? */
+       if (evt->notif.size < sizeof(*be) + sizeof(*bf)) {
+               dev_err(dev, "BEACON event: Not enough data to decode "
+                       "(%zu vs %zu bytes needed)\n", evt->notif.size,
+                       sizeof(*be) + sizeof(*bf));
+               goto error;
+       }
+       /* FIXME: make sure beacon frame IEs are fine and that the whole thing
+        * is consistent */
+       result = 0;
+error:
+       return result;
+}
+
+/*
+ * Handle UWB_RC_EVT_BEACON events
+ *
+ * We check the beacon cache to see how the received beacon fares. If
+ * is there already we refresh the timestamp. If not we create a new
+ * entry.
+ *
+ * According to the WHCI and WUSB specs, only one beacon frame is
+ * allowed per notification block, so we don't bother about scanning
+ * for more.
+ */
+int uwbd_evt_handle_rc_beacon(struct uwb_event *evt)
+{
+       int result = -EINVAL;
+       struct uwb_rc *rc;
+       struct uwb_rc_evt_beacon *be;
+       struct uwb_beacon_frame *bf;
+       struct uwb_beca_e *bce;
+
+       rc = evt->rc;
+       be = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon, rceb);
+       result = uwb_verify_beacon(rc, evt, be);
+       if (result < 0)
+               return result;
+
+       /* FIXME: handle alien beacons. */
+       if (be->bBeaconType == UWB_RC_BEACON_TYPE_OL_ALIEN ||
+           be->bBeaconType == UWB_RC_BEACON_TYPE_NOL_ALIEN) {
+               return -ENOSYS;
+       }
+
+       bf = (struct uwb_beacon_frame *) be->BeaconInfo;
+
+       /*
+        * Drop beacons from devices with a NULL EUI-48 -- they cannot
+        * be uniquely identified.
+        *
+        * It's expected that these will all be WUSB devices and they
+        * have a WUSB specific connection method so ignoring them
+        * here shouldn't be a problem.
+        */
+       if (uwb_mac_addr_bcast(&bf->Device_Identifier))
+               return 0;
+
+       mutex_lock(&rc->uwb_beca.mutex);
+       bce = __uwb_beca_find_bymac(rc, &bf->Device_Identifier);
+       if (bce == NULL) {
+               /* Not in there, a new device is pinging */
+               uwb_beacon_print(evt->rc, be, bf);
+               bce = __uwb_beca_add(rc, be, bf, evt->ts_jiffies);
+               if (bce == NULL) {
+                       mutex_unlock(&rc->uwb_beca.mutex);
+                       return -ENOMEM;
+               }
+       }
+       mutex_unlock(&rc->uwb_beca.mutex);
+
+       mutex_lock(&bce->mutex);
+       /* purge old beacon data */
+       kfree(bce->be);
+
+       /* Update commonly used fields */
+       bce->ts_jiffies = evt->ts_jiffies;
+       bce->be = be;
+       bce->dev_addr = bf->hdr.SrcAddr;
+       bce->mac_addr = &bf->Device_Identifier;
+       be->wBPSTOffset = le16_to_cpu(be->wBPSTOffset);
+       be->wBeaconInfoLength = le16_to_cpu(be->wBeaconInfoLength);
+       stats_add_sample(&bce->lqe_stats, be->bLQI - 7);
+       stats_add_sample(&bce->rssi_stats, be->bRSSI + 18);
+
+       /*
+        * This might be a beacon from a new device.
+        */
+       if (bce->uwb_dev == NULL)
+               uwbd_dev_onair(evt->rc, bce);
+
+       mutex_unlock(&bce->mutex);
+
+       return 1; /* we keep the event data */
+}
+
+/*
+ * Handle UWB_RC_EVT_BEACON_SIZE events
+ *
+ * XXXXX
+ */
+int uwbd_evt_handle_rc_beacon_size(struct uwb_event *evt)
+{
+       int result = -EINVAL;
+       struct device *dev = &evt->rc->uwb_dev.dev;
+       struct uwb_rc_evt_beacon_size *bs;
+
+       /* Is there enough data to decode the event? */
+       if (evt->notif.size < sizeof(*bs)) {
+               dev_err(dev, "BEACON SIZE notification: Not enough data to "
+                       "decode (%zu vs %zu bytes needed)\n",
+                       evt->notif.size, sizeof(*bs));
+               goto error;
+       }
+       bs = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon_size, rceb);
+       if (0)
+               dev_info(dev, "Beacon size changed to %u bytes "
+                       "(FIXME: action?)\n", le16_to_cpu(bs->wNewBeaconSize));
+       else {
+               /* temporary hack until we do something with this message... */
+               static unsigned count;
+               if (++count % 1000 == 0)
+                       dev_info(dev, "Beacon size changed %u times "
+                               "(FIXME: action?)\n", count);
+       }
+       result = 0;
+error:
+       return result;
+}
+
+/**
+ * uwbd_evt_handle_rc_bp_slot_change - handle a BP_SLOT_CHANGE event
+ * @evt: the BP_SLOT_CHANGE notification from the radio controller
+ *
+ * If the event indicates that no beacon period slots were available
+ * then radio controller has transitioned to a non-beaconing state.
+ * Otherwise, simply save the current beacon slot.
+ */
+int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *evt)
+{
+       struct uwb_rc *rc = evt->rc;
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_rc_evt_bp_slot_change *bpsc;
+
+       if (evt->notif.size < sizeof(*bpsc)) {
+               dev_err(dev, "BP SLOT CHANGE event: Not enough data\n");
+               return -EINVAL;
+       }
+       bpsc = container_of(evt->notif.rceb, struct uwb_rc_evt_bp_slot_change, rceb);
+
+       if (uwb_rc_evt_bp_slot_change_no_slot(bpsc)) {
+               dev_err(dev, "stopped beaconing: No free slots in BP\n");
+               mutex_lock(&rc->uwb_dev.mutex);
+               rc->beaconing = -1;
+               mutex_unlock(&rc->uwb_dev.mutex);
+       } else
+               rc->uwb_dev.beacon_slot = uwb_rc_evt_bp_slot_change_slot_num(bpsc);
+
+       return 0;
+}
+
+/**
+ * Handle UWB_RC_EVT_BPOIE_CHANGE events
+ *
+ * XXXXX
+ */
+struct uwb_ie_bpo {
+       struct uwb_ie_hdr hdr;
+       u8                bp_length;
+       u8                data[];
+} __attribute__((packed));
+
+int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *evt)
+{
+       int result = -EINVAL;
+       struct device *dev = &evt->rc->uwb_dev.dev;
+       struct uwb_rc_evt_bpoie_change *bpoiec;
+       struct uwb_ie_bpo *bpoie;
+       static unsigned count;  /* FIXME: this is a temp hack */
+       size_t iesize;
+
+       /* Is there enough data to decode it? */
+       if (evt->notif.size < sizeof(*bpoiec)) {
+               dev_err(dev, "BPOIEC notification: Not enough data to "
+                       "decode (%zu vs %zu bytes needed)\n",
+                       evt->notif.size, sizeof(*bpoiec));
+               goto error;
+       }
+       bpoiec = container_of(evt->notif.rceb, struct uwb_rc_evt_bpoie_change, rceb);
+       iesize = le16_to_cpu(bpoiec->wBPOIELength);
+       if (iesize < sizeof(*bpoie)) {
+               dev_err(dev, "BPOIEC notification: Not enough IE data to "
+                       "decode (%zu vs %zu bytes needed)\n",
+                       iesize, sizeof(*bpoie));
+               goto error;
+       }
+       if (++count % 1000 == 0)        /* Lame placeholder */
+               dev_info(dev, "BPOIE: %u changes received\n", count);
+       /*
+        * FIXME: At this point we should go over all the IEs in the
+        *        bpoiec->BPOIE array and act on each.
+        */
+       result = 0;
+error:
+       return result;
+}
+
+/*
+ * Print beaconing state.
+ */
+static ssize_t uwb_rc_beacon_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;
+       ssize_t result;
+
+       mutex_lock(&rc->uwb_dev.mutex);
+       result = sprintf(buf, "%d\n", rc->beaconing);
+       mutex_unlock(&rc->uwb_dev.mutex);
+       return result;
+}
+
+/*
+ * Start beaconing on the specified channel, or stop beaconing.
+ */
+static ssize_t uwb_rc_beacon_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;
+       int channel;
+       ssize_t result = -EINVAL;
+
+       result = sscanf(buf, "%d", &channel);
+       if (result >= 1)
+               result = uwb_radio_force_channel(rc, channel);
+
+       return result < 0 ? result : size;
+}
+DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, uwb_rc_beacon_show, uwb_rc_beacon_store);
diff --git a/drivers/staging/uwb/driver.c b/drivers/staging/uwb/driver.c
new file mode 100644 (file)
index 0000000..5755c2e
--- /dev/null
@@ -0,0 +1,143 @@
+// 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");
diff --git a/drivers/staging/uwb/drp-avail.c b/drivers/staging/uwb/drp-avail.c
new file mode 100644 (file)
index 0000000..02392ab
--- /dev/null
@@ -0,0 +1,278 @@
+// 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;
+}
diff --git a/drivers/staging/uwb/drp-ie.c b/drivers/staging/uwb/drp-ie.c
new file mode 100644 (file)
index 0000000..b2a862c
--- /dev/null
@@ -0,0 +1,305 @@
+// 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);
+               }
+       }
+}
+
diff --git a/drivers/staging/uwb/drp.c b/drivers/staging/uwb/drp.c
new file mode 100644 (file)
index 0000000..869987b
--- /dev/null
@@ -0,0 +1,842 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Dynamic Reservation Protocol handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "uwb-internal.h"
+
+
+/* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */
+enum uwb_drp_conflict_action {
+       /* Reservation is maintained, no action needed */
+       UWB_DRP_CONFLICT_MANTAIN = 0,
+
+       /* the device shall not transmit frames in conflicting MASs in
+        * the following superframe. If the device is the reservation
+        * target, it shall also set the Reason Code in its DRP IE to
+        * Conflict in its beacon in the following superframe.
+        */
+       UWB_DRP_CONFLICT_ACT1,
+
+       /* the device shall not set the Reservation Status bit to ONE
+        * and shall not transmit frames in conflicting MASs. If the
+        * device is the reservation target, it shall also set the
+        * Reason Code in its DRP IE to Conflict.
+        */
+       UWB_DRP_CONFLICT_ACT2,
+
+       /* the device shall not transmit frames in conflicting MASs in
+        * the following superframe. It shall remove the conflicting
+        * MASs from the reservation or set the Reservation Status to
+        * ZERO in its beacon in the following superframe. If the
+        * device is the reservation target, it shall also set the
+        * Reason Code in its DRP IE to Conflict.
+        */
+       UWB_DRP_CONFLICT_ACT3,
+};
+
+
+static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg,
+                                   struct uwb_rceb *reply, ssize_t reply_size)
+{
+       struct uwb_rc_evt_set_drp_ie *r = (struct uwb_rc_evt_set_drp_ie *)reply;
+       unsigned long flags;
+
+       if (r != NULL) {
+               if (r->bResultCode != UWB_RC_RES_SUCCESS)
+                       dev_err(&rc->uwb_dev.dev, "SET-DRP-IE failed: %s (%d)\n",
+                               uwb_rc_strerror(r->bResultCode), r->bResultCode);
+       } else
+               dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n");
+
+       spin_lock_irqsave(&rc->rsvs_lock, flags);
+       if (rc->set_drp_ie_pending > 1) {
+               rc->set_drp_ie_pending = 0;
+               uwb_rsv_queue_update(rc);
+       } else {
+               rc->set_drp_ie_pending = 0;
+       }
+       spin_unlock_irqrestore(&rc->rsvs_lock, flags);
+}
+
+/**
+ * Construct and send the SET DRP IE
+ *
+ * @rc:         UWB Host controller
+ * @returns:    >= 0 number of bytes still available in the beacon
+ *              < 0 errno code on error.
+ *
+ * See WUSB[8.6.2.7]: The host must set all the DRP IEs that it wants the
+ * device to include in its beacon at the same time. We thus have to
+ * traverse all reservations and include the DRP IEs of all PENDING
+ * and NEGOTIATED reservations in a SET DRP command for transmission.
+ *
+ * A DRP Availability IE is appended.
+ *
+ * rc->rsvs_mutex is held
+ *
+ * FIXME We currently ignore the returned value indicating the remaining space
+ * in beacon. This could be used to deny reservation requests earlier if
+ * determined that they would cause the beacon space to be exceeded.
+ */
+int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
+{
+       int result;
+       struct uwb_rc_cmd_set_drp_ie *cmd;
+       struct uwb_rsv *rsv;
+       struct uwb_rsv_move *mv;
+       int num_bytes = 0;
+       u8 *IEDataptr;
+
+       result = -ENOMEM;
+       /* First traverse all reservations to determine memory needed. */
+       list_for_each_entry(rsv, &rc->reservations, rc_node) {
+               if (rsv->drp_ie != NULL) {
+                       num_bytes += rsv->drp_ie->hdr.length + 2;
+                       if (uwb_rsv_has_two_drp_ies(rsv) &&
+                               (rsv->mv.companion_drp_ie != NULL)) {
+                               mv = &rsv->mv;
+                               num_bytes +=
+                                       mv->companion_drp_ie->hdr.length + 2;
+                       }
+               }
+       }
+       num_bytes += sizeof(rc->drp_avail.ie);
+       cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL);
+       if (cmd == NULL)
+               goto error;
+       cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+       cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_DRP_IE);
+       cmd->wIELength = num_bytes;
+       IEDataptr = (u8 *)&cmd->IEData[0];
+
+       /* FIXME: DRV avail IE is not always needed */
+       /* put DRP avail IE first */
+       memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie));
+       IEDataptr += sizeof(struct uwb_ie_drp_avail);
+
+       /* Next traverse all reservations to place IEs in allocated memory. */
+       list_for_each_entry(rsv, &rc->reservations, rc_node) {
+               if (rsv->drp_ie != NULL) {
+                       memcpy(IEDataptr, rsv->drp_ie,
+                              rsv->drp_ie->hdr.length + 2);
+                       IEDataptr += rsv->drp_ie->hdr.length + 2;
+
+                       if (uwb_rsv_has_two_drp_ies(rsv) &&
+                               (rsv->mv.companion_drp_ie != NULL)) {
+                               mv = &rsv->mv;
+                               memcpy(IEDataptr, mv->companion_drp_ie,
+                                      mv->companion_drp_ie->hdr.length + 2);
+                               IEDataptr +=
+                                       mv->companion_drp_ie->hdr.length + 2;
+                       }
+               }
+       }
+
+       result = uwb_rc_cmd_async(rc, "SET-DRP-IE",
+                               &cmd->rccb, sizeof(*cmd) + num_bytes,
+                               UWB_RC_CET_GENERAL, UWB_RC_CMD_SET_DRP_IE,
+                               uwb_rc_set_drp_cmd_done, NULL);
+
+       rc->set_drp_ie_pending = 1;
+
+       kfree(cmd);
+error:
+       return result;
+}
+
+/*
+ * Evaluate the action to perform using conflict resolution rules
+ *
+ * Return a uwb_drp_conflict_action.
+ */
+static int evaluate_conflict_action(struct uwb_ie_drp *ext_drp_ie, int ext_beacon_slot,
+                                   struct uwb_rsv *rsv, int our_status)
+{
+       int our_tie_breaker = rsv->tiebreaker;
+       int our_type        = rsv->type;
+       int our_beacon_slot = rsv->rc->uwb_dev.beacon_slot;
+
+       int ext_tie_breaker = uwb_ie_drp_tiebreaker(ext_drp_ie);
+       int ext_status      = uwb_ie_drp_status(ext_drp_ie);
+       int ext_type        = uwb_ie_drp_type(ext_drp_ie);
+
+
+       /* [ECMA-368 2nd Edition] 17.4.6 */
+       if (ext_type == UWB_DRP_TYPE_PCA && our_type == UWB_DRP_TYPE_PCA) {
+               return UWB_DRP_CONFLICT_MANTAIN;
+       }
+
+       /* [ECMA-368 2nd Edition] 17.4.6-1 */
+       if (our_type == UWB_DRP_TYPE_ALIEN_BP) {
+               return UWB_DRP_CONFLICT_MANTAIN;
+       }
+
+       /* [ECMA-368 2nd Edition] 17.4.6-2 */
+       if (ext_type == UWB_DRP_TYPE_ALIEN_BP) {
+               /* here we know our_type != UWB_DRP_TYPE_ALIEN_BP */
+               return UWB_DRP_CONFLICT_ACT1;
+       }
+
+       /* [ECMA-368 2nd Edition] 17.4.6-3 */
+       if (our_status == 0 && ext_status == 1) {
+               return UWB_DRP_CONFLICT_ACT2;
+       }
+
+       /* [ECMA-368 2nd Edition] 17.4.6-4 */
+       if (our_status == 1 && ext_status == 0) {
+               return UWB_DRP_CONFLICT_MANTAIN;
+       }
+
+       /* [ECMA-368 2nd Edition] 17.4.6-5a */
+       if (our_tie_breaker == ext_tie_breaker &&
+           our_beacon_slot <  ext_beacon_slot) {
+               return UWB_DRP_CONFLICT_MANTAIN;
+       }
+
+       /* [ECMA-368 2nd Edition] 17.4.6-5b */
+       if (our_tie_breaker != ext_tie_breaker &&
+           our_beacon_slot >  ext_beacon_slot) {
+               return UWB_DRP_CONFLICT_MANTAIN;
+       }
+
+       if (our_status == 0) {
+               if (our_tie_breaker == ext_tie_breaker) {
+                       /* [ECMA-368 2nd Edition] 17.4.6-6a */
+                       if (our_beacon_slot > ext_beacon_slot) {
+                               return UWB_DRP_CONFLICT_ACT2;
+                       }
+               } else  {
+                       /* [ECMA-368 2nd Edition] 17.4.6-6b */
+                       if (our_beacon_slot < ext_beacon_slot) {
+                               return UWB_DRP_CONFLICT_ACT2;
+                       }
+               }
+       } else {
+               if (our_tie_breaker == ext_tie_breaker) {
+                       /* [ECMA-368 2nd Edition] 17.4.6-7a */
+                       if (our_beacon_slot > ext_beacon_slot) {
+                               return UWB_DRP_CONFLICT_ACT3;
+                       }
+               } else {
+                       /* [ECMA-368 2nd Edition] 17.4.6-7b */
+                       if (our_beacon_slot < ext_beacon_slot) {
+                               return UWB_DRP_CONFLICT_ACT3;
+                       }
+               }
+       }
+       return UWB_DRP_CONFLICT_MANTAIN;
+}
+
+static void handle_conflict_normal(struct uwb_ie_drp *drp_ie,
+                                  int ext_beacon_slot,
+                                  struct uwb_rsv *rsv,
+                                  struct uwb_mas_bm *conflicting_mas)
+{
+       struct uwb_rc *rc = rsv->rc;
+       struct uwb_rsv_move *mv = &rsv->mv;
+       struct uwb_drp_backoff_win *bow = &rc->bow;
+       int action;
+
+       action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, uwb_rsv_status(rsv));
+
+       if (uwb_rsv_is_owner(rsv)) {
+               switch(action) {
+               case UWB_DRP_CONFLICT_ACT2:
+                       /* try move */
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_TO_BE_MOVED);
+                       if (bow->can_reserve_extra_mases == false)
+                               uwb_rsv_backoff_win_increment(rc);
+
+                       break;
+               case UWB_DRP_CONFLICT_ACT3:
+                       uwb_rsv_backoff_win_increment(rc);
+                       /* drop some mases with reason modified */
+                       /* put in the companion the mases to be dropped */
+                       bitmap_and(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS);
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
+               default:
+                       break;
+               }
+       } else {
+               switch(action) {
+               case UWB_DRP_CONFLICT_ACT2:
+               case UWB_DRP_CONFLICT_ACT3:
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
+               default:
+                       break;
+               }
+
+       }
+
+}
+
+static void handle_conflict_expanding(struct uwb_ie_drp *drp_ie, int ext_beacon_slot,
+                                     struct uwb_rsv *rsv, bool companion_only,
+                                     struct uwb_mas_bm *conflicting_mas)
+{
+       struct uwb_rc *rc = rsv->rc;
+       struct uwb_drp_backoff_win *bow = &rc->bow;
+       struct uwb_rsv_move *mv = &rsv->mv;
+       int action;
+
+       if (companion_only) {
+               /* status of companion is 0 at this point */
+               action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, 0);
+               if (uwb_rsv_is_owner(rsv)) {
+                       switch(action) {
+                       case UWB_DRP_CONFLICT_ACT2:
+                       case UWB_DRP_CONFLICT_ACT3:
+                               uwb_rsv_set_state(rsv,
+                                               UWB_RSV_STATE_O_ESTABLISHED);
+                               rsv->needs_release_companion_mas = false;
+                               if (bow->can_reserve_extra_mases == false)
+                                       uwb_rsv_backoff_win_increment(rc);
+                               uwb_drp_avail_release(rsv->rc,
+                                               &rsv->mv.companion_mas);
+                       }
+               } else { /* rsv is target */
+                       switch(action) {
+                       case UWB_DRP_CONFLICT_ACT2:
+                       case UWB_DRP_CONFLICT_ACT3:
+                               uwb_rsv_set_state(rsv,
+                                       UWB_RSV_STATE_T_EXPANDING_CONFLICT);
+                                /* send_drp_avail_ie = true; */
+                       }
+               }
+       } else { /* also base part of the reservation is conflicting */
+               if (uwb_rsv_is_owner(rsv)) {
+                       uwb_rsv_backoff_win_increment(rc);
+                       /* remove companion part */
+                       uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
+
+                       /* drop some mases with reason modified */
+
+                       /* put in the companion the mases to be dropped */
+                       bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm,
+                                       conflicting_mas->bm, UWB_NUM_MAS);
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
+               } else { /* it is a target rsv */
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
+                        /* send_drp_avail_ie = true; */
+               }
+       }
+}
+
+static void uwb_drp_handle_conflict_rsv(struct uwb_rc *rc, struct uwb_rsv *rsv,
+                                       struct uwb_rc_evt_drp *drp_evt,
+                                       struct uwb_ie_drp *drp_ie,
+                                       struct uwb_mas_bm *conflicting_mas)
+{
+       struct uwb_rsv_move *mv;
+
+       /* check if the conflicting reservation has two drp_ies */
+       if (uwb_rsv_has_two_drp_ies(rsv)) {
+               mv = &rsv->mv;
+               if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
+                                                               UWB_NUM_MAS)) {
+                       handle_conflict_expanding(drp_ie,
+                                               drp_evt->beacon_slot_number,
+                                               rsv, false, conflicting_mas);
+               } else {
+                       if (bitmap_intersects(mv->companion_mas.bm,
+                                       conflicting_mas->bm, UWB_NUM_MAS)) {
+                               handle_conflict_expanding(
+                                       drp_ie, drp_evt->beacon_slot_number,
+                                       rsv, true, conflicting_mas);
+                       }
+               }
+       } else if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
+                                                       UWB_NUM_MAS)) {
+               handle_conflict_normal(drp_ie, drp_evt->beacon_slot_number,
+                                       rsv, conflicting_mas);
+       }
+}
+
+static void uwb_drp_handle_all_conflict_rsv(struct uwb_rc *rc,
+                                           struct uwb_rc_evt_drp *drp_evt,
+                                           struct uwb_ie_drp *drp_ie,
+                                           struct uwb_mas_bm *conflicting_mas)
+{
+       struct uwb_rsv *rsv;
+
+       list_for_each_entry(rsv, &rc->reservations, rc_node) {
+               uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie,
+                                                       conflicting_mas);
+       }
+}
+
+static void uwb_drp_process_target_accepted(struct uwb_rc *rc,
+       struct uwb_rsv *rsv, struct uwb_rc_evt_drp *drp_evt,
+       struct uwb_ie_drp *drp_ie, struct uwb_mas_bm *mas)
+{
+       struct uwb_rsv_move *mv = &rsv->mv;
+       int status;
+
+       status = uwb_ie_drp_status(drp_ie);
+
+       if (rsv->state == UWB_RSV_STATE_T_CONFLICT) {
+               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
+               return;
+       }
+
+       if (rsv->state == UWB_RSV_STATE_T_EXPANDING_ACCEPTED) {
+               /* drp_ie is companion */
+               if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
+                       /* stroke companion */
+                       uwb_rsv_set_state(rsv,
+                               UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
+               }
+       } else {
+               if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
+                       if (uwb_drp_avail_reserve_pending(rc, mas) == -EBUSY) {
+                               /* FIXME: there is a conflict, find
+                                * the conflicting reservations and
+                                * take a sensible action. Consider
+                                * that in drp_ie there is the
+                                * "neighbour" */
+                               uwb_drp_handle_all_conflict_rsv(rc, drp_evt,
+                                               drp_ie, mas);
+                       } else {
+                               /* accept the extra reservation */
+                               bitmap_copy(mv->companion_mas.bm, mas->bm,
+                                                               UWB_NUM_MAS);
+                               uwb_rsv_set_state(rsv,
+                                       UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
+                       }
+               } else {
+                       if (status) {
+                               uwb_rsv_set_state(rsv,
+                                               UWB_RSV_STATE_T_ACCEPTED);
+                       }
+               }
+
+       }
+}
+
+/*
+ * Based on the DRP IE, transition a target reservation to a new
+ * state.
+ */
+static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv,
+                  struct uwb_ie_drp *drp_ie, struct uwb_rc_evt_drp *drp_evt)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_rsv_move *mv = &rsv->mv;
+       int status;
+       enum uwb_drp_reason reason_code;
+       struct uwb_mas_bm mas;
+
+       status = uwb_ie_drp_status(drp_ie);
+       reason_code = uwb_ie_drp_reason_code(drp_ie);
+       uwb_drp_ie_to_bm(&mas, drp_ie);
+
+       switch (reason_code) {
+       case UWB_DRP_REASON_ACCEPTED:
+               uwb_drp_process_target_accepted(rc, rsv, drp_evt, drp_ie, &mas);
+               break;
+
+       case UWB_DRP_REASON_MODIFIED:
+               /* check to see if we have already modified the reservation */
+               if (bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) {
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
+                       break;
+               }
+
+               /* find if the owner wants to expand or reduce */
+               if (bitmap_subset(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) {
+                       /* owner is reducing */
+                       bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mas.bm,
+                               UWB_NUM_MAS);
+                       uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
+               }
+
+               bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS);
+               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_RESIZED);
+               break;
+       default:
+               dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+                        reason_code, status);
+       }
+}
+
+static void uwb_drp_process_owner_accepted(struct uwb_rsv *rsv,
+                                               struct uwb_mas_bm *mas)
+{
+       struct uwb_rsv_move *mv = &rsv->mv;
+
+       switch (rsv->state) {
+       case UWB_RSV_STATE_O_PENDING:
+       case UWB_RSV_STATE_O_INITIATED:
+       case UWB_RSV_STATE_O_ESTABLISHED:
+               uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+               break;
+       case UWB_RSV_STATE_O_MODIFIED:
+               if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+               else
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
+               break;
+
+       case UWB_RSV_STATE_O_MOVE_REDUCING: /* shouldn' t be a problem */
+               if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+               else
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
+               break;
+       case UWB_RSV_STATE_O_MOVE_EXPANDING:
+               if (bitmap_equal(mas->bm, mv->companion_mas.bm, UWB_NUM_MAS)) {
+                       /* Companion reservation accepted */
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
+               } else {
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
+               }
+               break;
+       case UWB_RSV_STATE_O_MOVE_COMBINING:
+               if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
+               else
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
+               break;
+       default:
+               break;
+       }
+}
+/*
+ * Based on the DRP IE, transition an owner reservation to a new
+ * state.
+ */
+static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv,
+                                 struct uwb_dev *src, struct uwb_ie_drp *drp_ie,
+                                 struct uwb_rc_evt_drp *drp_evt)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       int status;
+       enum uwb_drp_reason reason_code;
+       struct uwb_mas_bm mas;
+
+       status = uwb_ie_drp_status(drp_ie);
+       reason_code = uwb_ie_drp_reason_code(drp_ie);
+       uwb_drp_ie_to_bm(&mas, drp_ie);
+
+       if (status) {
+               switch (reason_code) {
+               case UWB_DRP_REASON_ACCEPTED:
+                       uwb_drp_process_owner_accepted(rsv, &mas);
+                       break;
+               default:
+                       dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+                                reason_code, status);
+               }
+       } else {
+               switch (reason_code) {
+               case UWB_DRP_REASON_PENDING:
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_PENDING);
+                       break;
+               case UWB_DRP_REASON_DENIED:
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+                       break;
+               case UWB_DRP_REASON_CONFLICT:
+                       /* resolve the conflict */
+                       bitmap_complement(mas.bm, src->last_availability_bm,
+                                         UWB_NUM_MAS);
+                       uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, &mas);
+                       break;
+               default:
+                       dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+                                reason_code, status);
+               }
+       }
+}
+
+static void uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien *cnflt)
+{
+       unsigned timeout_us = UWB_MAX_LOST_BEACONS * UWB_SUPERFRAME_LENGTH_US;
+       mod_timer(&cnflt->timer, jiffies + usecs_to_jiffies(timeout_us));
+}
+
+static void uwb_cnflt_update_work(struct work_struct *work)
+{
+       struct uwb_cnflt_alien *cnflt = container_of(work,
+                                                    struct uwb_cnflt_alien,
+                                                    cnflt_update_work);
+       struct uwb_cnflt_alien *c;
+       struct uwb_rc *rc = cnflt->rc;
+
+       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
+
+       mutex_lock(&rc->rsvs_mutex);
+
+       list_del(&cnflt->rc_node);
+
+       /* update rc global conflicting alien bitmap */
+       bitmap_zero(rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
+
+       list_for_each_entry(c, &rc->cnflt_alien_list, rc_node) {
+               bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm,
+                                               c->mas.bm, UWB_NUM_MAS);
+       }
+
+       queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work,
+                                       usecs_to_jiffies(delay_us));
+
+       kfree(cnflt);
+       mutex_unlock(&rc->rsvs_mutex);
+}
+
+static void uwb_cnflt_timer(struct timer_list *t)
+{
+       struct uwb_cnflt_alien *cnflt = from_timer(cnflt, t, timer);
+
+       queue_work(cnflt->rc->rsv_workq, &cnflt->cnflt_update_work);
+}
+
+/*
+ * We have received an DRP_IE of type Alien BP and we need to make
+ * sure we do not transmit in conflicting MASs.
+ */
+static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_mas_bm mas;
+       struct uwb_cnflt_alien *cnflt;
+       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
+
+       uwb_drp_ie_to_bm(&mas, drp_ie);
+
+       list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) {
+               if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) {
+                       /* Existing alien BP reservation conflicting
+                        * bitmap, just reset the timer */
+                       uwb_cnflt_alien_stroke_timer(cnflt);
+                       return;
+               }
+       }
+
+       /* New alien BP reservation conflicting bitmap */
+
+       /* alloc and initialize new uwb_cnflt_alien */
+       cnflt = kzalloc(sizeof(struct uwb_cnflt_alien), GFP_KERNEL);
+       if (!cnflt) {
+               dev_err(dev, "failed to alloc uwb_cnflt_alien struct\n");
+               return;
+       }
+
+       INIT_LIST_HEAD(&cnflt->rc_node);
+       timer_setup(&cnflt->timer, uwb_cnflt_timer, 0);
+
+       cnflt->rc = rc;
+       INIT_WORK(&cnflt->cnflt_update_work, uwb_cnflt_update_work);
+
+       bitmap_copy(cnflt->mas.bm, mas.bm, UWB_NUM_MAS);
+
+       list_add_tail(&cnflt->rc_node, &rc->cnflt_alien_list);
+
+       /* update rc global conflicting alien bitmap */
+       bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, mas.bm, UWB_NUM_MAS);
+
+       queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us));
+
+       /* start the timer */
+       uwb_cnflt_alien_stroke_timer(cnflt);
+}
+
+static void uwb_drp_process_not_involved(struct uwb_rc *rc,
+                                        struct uwb_rc_evt_drp *drp_evt,
+                                        struct uwb_ie_drp *drp_ie)
+{
+       struct uwb_mas_bm mas;
+
+       uwb_drp_ie_to_bm(&mas, drp_ie);
+       uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas);
+}
+
+static void uwb_drp_process_involved(struct uwb_rc *rc, struct uwb_dev *src,
+                                    struct uwb_rc_evt_drp *drp_evt,
+                                    struct uwb_ie_drp *drp_ie)
+{
+       struct uwb_rsv *rsv;
+
+       rsv = uwb_rsv_find(rc, src, drp_ie);
+       if (!rsv) {
+               /*
+                * No reservation? It's either for a recently
+                * terminated reservation; or the DRP IE couldn't be
+                * processed (e.g., an invalid IE or out of memory).
+                */
+               return;
+       }
+
+       /*
+        * Do nothing with DRP IEs for reservations that have been
+        * terminated.
+        */
+       if (rsv->state == UWB_RSV_STATE_NONE) {
+               uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+               return;
+       }
+
+       if (uwb_ie_drp_owner(drp_ie))
+               uwb_drp_process_target(rc, rsv, drp_ie, drp_evt);
+       else
+               uwb_drp_process_owner(rc, rsv, src, drp_ie, drp_evt);
+
+}
+
+
+static bool uwb_drp_involves_us(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
+{
+       return uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, &drp_ie->dev_addr) == 0;
+}
+
+/*
+ * Process a received DRP IE.
+ */
+static void uwb_drp_process(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
+                           struct uwb_dev *src, struct uwb_ie_drp *drp_ie)
+{
+       if (uwb_ie_drp_type(drp_ie) == UWB_DRP_TYPE_ALIEN_BP)
+               uwb_drp_handle_alien_drp(rc, drp_ie);
+       else if (uwb_drp_involves_us(rc, drp_ie))
+               uwb_drp_process_involved(rc, src, drp_evt, drp_ie);
+       else
+               uwb_drp_process_not_involved(rc, drp_evt, drp_ie);
+}
+
+/*
+ * Process a received DRP Availability IE
+ */
+static void uwb_drp_availability_process(struct uwb_rc *rc, struct uwb_dev *src,
+                                        struct uwb_ie_drp_avail *drp_availability_ie)
+{
+       bitmap_copy(src->last_availability_bm,
+                   drp_availability_ie->bmp, UWB_NUM_MAS);
+}
+
+/*
+ * Process all the DRP IEs (both DRP IEs and the DRP Availability IE)
+ * from a device.
+ */
+static
+void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
+                        size_t ielen, struct uwb_dev *src_dev)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_ie_hdr *ie_hdr;
+       void *ptr;
+
+       ptr = drp_evt->ie_data;
+       for (;;) {
+               ie_hdr = uwb_ie_next(&ptr, &ielen);
+               if (!ie_hdr)
+                       break;
+
+               switch (ie_hdr->element_id) {
+               case UWB_IE_DRP_AVAILABILITY:
+                       uwb_drp_availability_process(rc, src_dev, (struct uwb_ie_drp_avail *)ie_hdr);
+                       break;
+               case UWB_IE_DRP:
+                       uwb_drp_process(rc, drp_evt, src_dev, (struct uwb_ie_drp *)ie_hdr);
+                       break;
+               default:
+                       dev_warn(dev, "unexpected IE in DRP notification\n");
+                       break;
+               }
+       }
+
+       if (ielen > 0)
+               dev_warn(dev, "%d octets remaining in DRP notification\n",
+                        (int)ielen);
+}
+
+/**
+ * uwbd_evt_handle_rc_drp - handle a DRP_IE event
+ * @evt: the DRP_IE event from the radio controller
+ *
+ * This processes DRP notifications from the radio controller, either
+ * initiating a new reservation or transitioning an existing
+ * reservation into a different state.
+ *
+ * DRP notifications can occur for three different reasons:
+ *
+ * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as
+ *   the target or source have been received.
+ *
+ *   These DRP IEs could be new or for an existing reservation.
+ *
+ *   If the DRP IE for an existing reservation ceases to be to
+ *   received for at least mMaxLostBeacons, the reservation should be
+ *   considered to be terminated.  Note that the TERMINATE reason (see
+ *   below) may not always be signalled (e.g., the remote device has
+ *   two or more reservations established with the RC).
+ *
+ * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon
+ *   group conflict with the RC's reservations.
+ *
+ * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received
+ *   from a device (i.e., it's terminated all reservations).
+ *
+ * Only the software state of the reservations is changed; the setting
+ * of the radio controller's DRP IEs is done after all the events in
+ * an event buffer are processed.  This saves waiting multiple times
+ * for the SET_DRP_IE command to complete.
+ */
+int uwbd_evt_handle_rc_drp(struct uwb_event *evt)
+{
+       struct device *dev = &evt->rc->uwb_dev.dev;
+       struct uwb_rc *rc = evt->rc;
+       struct uwb_rc_evt_drp *drp_evt;
+       size_t ielength, bytes_left;
+       struct uwb_dev_addr src_addr;
+       struct uwb_dev *src_dev;
+
+       /* Is there enough data to decode the event (and any IEs in
+          its payload)? */
+       if (evt->notif.size < sizeof(*drp_evt)) {
+               dev_err(dev, "DRP event: Not enough data to decode event "
+                       "[%zu bytes left, %zu needed]\n",
+                       evt->notif.size, sizeof(*drp_evt));
+               return 0;
+       }
+       bytes_left = evt->notif.size - sizeof(*drp_evt);
+       drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp, rceb);
+       ielength = le16_to_cpu(drp_evt->ie_length);
+       if (bytes_left != ielength) {
+               dev_err(dev, "DRP event: Not enough data in payload [%zu"
+                       "bytes left, %zu declared in the event]\n",
+                       bytes_left, ielength);
+               return 0;
+       }
+
+       memcpy(src_addr.data, &drp_evt->src_addr, sizeof(src_addr));
+       src_dev = uwb_dev_get_by_devaddr(rc, &src_addr);
+       if (!src_dev) {
+               /*
+                * A DRP notification from an unrecognized device.
+                *
+                * This is probably from a WUSB device that doesn't
+                * have an EUI-48 and therefore doesn't show up in the
+                * UWB device database.  It's safe to simply ignore
+                * these.
+                */
+               return 0;
+       }
+
+       mutex_lock(&rc->rsvs_mutex);
+
+       /* We do not distinguish from the reason */
+       uwb_drp_process_all(rc, drp_evt, ielength, src_dev);
+
+       mutex_unlock(&rc->rsvs_mutex);
+
+       uwb_dev_put(src_dev);
+       return 0;
+}
diff --git a/drivers/staging/uwb/est.c b/drivers/staging/uwb/est.c
new file mode 100644 (file)
index 0000000..d4141ff
--- /dev/null
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band Radio Control
+ * Event Size Tables management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ *
+ * Infrastructure, code and data tables for guessing the size of
+ * events received on the notification endpoints of UWB radio
+ * controllers.
+ *
+ * You define a table of events and for each, its size and how to get
+ * the extra size.
+ *
+ * ENTRY POINTS:
+ *
+ * uwb_est_{init/destroy}(): To initialize/release the EST subsystem.
+ *
+ * uwb_est_[u]register(): To un/register event size tables
+ *   uwb_est_grow()
+ *
+ * uwb_est_find_size(): Get the size of an event
+ *   uwb_est_get_size()
+ */
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "uwb-internal.h"
+
+struct uwb_est {
+       u16 type_event_high;
+       u16 vendor, product;
+       u8 entries;
+       const struct uwb_est_entry *entry;
+};
+
+static struct uwb_est *uwb_est;
+static u8 uwb_est_size;
+static u8 uwb_est_used;
+static DEFINE_RWLOCK(uwb_est_lock);
+
+/**
+ * WUSB Standard Event Size Table, HWA-RC interface
+ *
+ * Sizes for events and notifications type 0 (general), high nibble 0.
+ */
+static
+struct uwb_est_entry uwb_est_00_00xx[] = {
+       [UWB_RC_EVT_IE_RCV] = {
+               .size = sizeof(struct uwb_rc_evt_ie_rcv),
+               .offset = 1 + offsetof(struct uwb_rc_evt_ie_rcv, wIELength),
+       },
+       [UWB_RC_EVT_BEACON] = {
+               .size = sizeof(struct uwb_rc_evt_beacon),
+               .offset = 1 + offsetof(struct uwb_rc_evt_beacon, wBeaconInfoLength),
+       },
+       [UWB_RC_EVT_BEACON_SIZE] = {
+               .size = sizeof(struct uwb_rc_evt_beacon_size),
+       },
+       [UWB_RC_EVT_BPOIE_CHANGE] = {
+               .size = sizeof(struct uwb_rc_evt_bpoie_change),
+               .offset = 1 + offsetof(struct uwb_rc_evt_bpoie_change,
+                                      wBPOIELength),
+       },
+       [UWB_RC_EVT_BP_SLOT_CHANGE] = {
+               .size = sizeof(struct uwb_rc_evt_bp_slot_change),
+       },
+       [UWB_RC_EVT_BP_SWITCH_IE_RCV] = {
+               .size = sizeof(struct uwb_rc_evt_bp_switch_ie_rcv),
+               .offset = 1 + offsetof(struct uwb_rc_evt_bp_switch_ie_rcv, wIELength),
+       },
+       [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
+               .size = sizeof(struct uwb_rc_evt_dev_addr_conflict),
+       },
+       [UWB_RC_EVT_DRP_AVAIL] = {
+               .size = sizeof(struct uwb_rc_evt_drp_avail)
+       },
+       [UWB_RC_EVT_DRP] = {
+               .size = sizeof(struct uwb_rc_evt_drp),
+               .offset = 1 + offsetof(struct uwb_rc_evt_drp, ie_length),
+       },
+       [UWB_RC_EVT_BP_SWITCH_STATUS] = {
+               .size = sizeof(struct uwb_rc_evt_bp_switch_status),
+       },
+       [UWB_RC_EVT_CMD_FRAME_RCV] = {
+               .size = sizeof(struct uwb_rc_evt_cmd_frame_rcv),
+               .offset = 1 + offsetof(struct uwb_rc_evt_cmd_frame_rcv, dataLength),
+       },
+       [UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV] = {
+               .size = sizeof(struct uwb_rc_evt_channel_change_ie_rcv),
+               .offset = 1 + offsetof(struct uwb_rc_evt_channel_change_ie_rcv, wIELength),
+       },
+       [UWB_RC_CMD_CHANNEL_CHANGE] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_DEV_ADDR_MGMT] = {
+               .size = sizeof(struct uwb_rc_evt_dev_addr_mgmt) },
+       [UWB_RC_CMD_GET_IE] = {
+               .size = sizeof(struct uwb_rc_evt_get_ie),
+               .offset = 1 + offsetof(struct uwb_rc_evt_get_ie, wIELength),
+       },
+       [UWB_RC_CMD_RESET] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_SCAN] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_SET_BEACON_FILTER] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_SET_DRP_IE] = {
+               .size = sizeof(struct uwb_rc_evt_set_drp_ie),
+       },
+       [UWB_RC_CMD_SET_IE] = {
+               .size = sizeof(struct uwb_rc_evt_set_ie),
+       },
+       [UWB_RC_CMD_SET_NOTIFICATION_FILTER] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_SET_TX_POWER] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_SLEEP] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_START_BEACON] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_STOP_BEACON] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_BP_MERGE] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_SEND_COMMAND_FRAME] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+       [UWB_RC_CMD_SET_ASIE_NOTIF] = {
+               .size = sizeof(struct uwb_rc_evt_confirm),
+       },
+};
+
+static
+struct uwb_est_entry uwb_est_01_00xx[] = {
+       [UWB_RC_DAA_ENERGY_DETECTED] = {
+               .size = sizeof(struct uwb_rc_evt_daa_energy_detected),
+       },
+       [UWB_RC_SET_DAA_ENERGY_MASK] = {
+               .size = sizeof(struct uwb_rc_evt_set_daa_energy_mask),
+       },
+       [UWB_RC_SET_NOTIFICATION_FILTER_EX] = {
+               .size = sizeof(struct uwb_rc_evt_set_notification_filter_ex),
+       },
+};
+
+/**
+ * Initialize the EST subsystem
+ *
+ * Register the standard tables also.
+ *
+ * FIXME: tag init
+ */
+int uwb_est_create(void)
+{
+       int result;
+
+       uwb_est_size = 2;
+       uwb_est_used = 0;
+       uwb_est = kcalloc(uwb_est_size, sizeof(uwb_est[0]), GFP_KERNEL);
+       if (uwb_est == NULL)
+               return -ENOMEM;
+
+       result = uwb_est_register(UWB_RC_CET_GENERAL, 0, 0xffff, 0xffff,
+                                 uwb_est_00_00xx, ARRAY_SIZE(uwb_est_00_00xx));
+       if (result < 0)
+               goto out;
+       result = uwb_est_register(UWB_RC_CET_EX_TYPE_1, 0, 0xffff, 0xffff,
+                                 uwb_est_01_00xx, ARRAY_SIZE(uwb_est_01_00xx));
+out:
+       return result;
+}
+
+
+/** Clean it up */
+void uwb_est_destroy(void)
+{
+       kfree(uwb_est);
+       uwb_est = NULL;
+       uwb_est_size = uwb_est_used = 0;
+}
+
+
+/**
+ * Double the capacity of the EST table
+ *
+ * @returns 0 if ok, < 0 errno no error.
+ */
+static
+int uwb_est_grow(void)
+{
+       size_t actual_size = uwb_est_size * sizeof(uwb_est[0]);
+       void *new = kmalloc_array(2, actual_size, GFP_ATOMIC);
+       if (new == NULL)
+               return -ENOMEM;
+       memcpy(new, uwb_est, actual_size);
+       memset(new + actual_size, 0, actual_size);
+       kfree(uwb_est);
+       uwb_est = new;
+       uwb_est_size *= 2;
+       return 0;
+}
+
+
+/**
+ * Register an event size table
+ *
+ * Makes room for it if the table is full, and then inserts  it in the
+ * right position (entries are sorted by type, event_high, vendor and
+ * then product).
+ *
+ * @vendor:  vendor code for matching against the device (0x0000 and
+ *           0xffff mean any); use 0x0000 to force all to match without
+ *           checking possible vendor specific ones, 0xfffff to match
+ *           after checking vendor specific ones.
+ *
+ * @product: product code from that vendor; same matching rules, use
+ *           0x0000 for not allowing vendor specific matches, 0xffff
+ *           for allowing.
+ *
+ * This arragement just makes the tables sort differenty. Because the
+ * table is sorted by growing type-event_high-vendor-product, a zero
+ * vendor will match before than a 0x456a vendor, that will match
+ * before a 0xfffff vendor.
+ *
+ * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
+ */
+/* FIXME: add bus type to vendor/product code */
+int uwb_est_register(u8 type, u8 event_high, u16 vendor, u16 product,
+                    const struct uwb_est_entry *entry, size_t entries)
+{
+       unsigned long flags;
+       unsigned itr;
+       int result = 0;
+
+       write_lock_irqsave(&uwb_est_lock, flags);
+       if (uwb_est_used == uwb_est_size) {
+               result = uwb_est_grow();
+               if (result < 0)
+                       goto out;
+       }
+       /* Find the right spot to insert it in */
+       for (itr = 0; itr < uwb_est_used; itr++)
+               if (uwb_est[itr].type_event_high < type
+                   && uwb_est[itr].vendor < vendor
+                   && uwb_est[itr].product < product)
+                       break;
+
+       /* Shift others to make room for the new one? */
+       if (itr < uwb_est_used)
+               memmove(&uwb_est[itr+1], &uwb_est[itr], uwb_est_used - itr);
+       uwb_est[itr].type_event_high = type << 8 | event_high;
+       uwb_est[itr].vendor = vendor;
+       uwb_est[itr].product = product;
+       uwb_est[itr].entry = entry;
+       uwb_est[itr].entries = entries;
+       uwb_est_used++;
+out:
+       write_unlock_irqrestore(&uwb_est_lock, flags);
+       return result;
+}
+EXPORT_SYMBOL_GPL(uwb_est_register);
+
+
+/**
+ * Unregister an event size table
+ *
+ * This just removes the specified entry and moves the ones after it
+ * to fill in the gap. This is needed to keep the list sorted; no
+ * reallocation is done to reduce the size of the table.
+ *
+ * We unregister by all the data we used to register instead of by
+ * pointer to the @entry array because we might have used the same
+ * table for a bunch of IDs (for example).
+ *
+ * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
+ */
+int uwb_est_unregister(u8 type, u8 event_high, u16 vendor, u16 product,
+                      const struct uwb_est_entry *entry, size_t entries)
+{
+       unsigned long flags;
+       unsigned itr;
+       struct uwb_est est_cmp = {
+               .type_event_high = type << 8 | event_high,
+               .vendor = vendor,
+               .product = product,
+               .entry = entry,
+               .entries = entries
+       };
+       write_lock_irqsave(&uwb_est_lock, flags);
+       for (itr = 0; itr < uwb_est_used; itr++)
+               if (!memcmp(&uwb_est[itr], &est_cmp, sizeof(est_cmp)))
+                       goto found;
+       write_unlock_irqrestore(&uwb_est_lock, flags);
+       return -ENOENT;
+
+found:
+       if (itr < uwb_est_used - 1)     /* Not last one? move ones above */
+               memmove(&uwb_est[itr], &uwb_est[itr+1], uwb_est_used - itr - 1);
+       uwb_est_used--;
+       write_unlock_irqrestore(&uwb_est_lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_est_unregister);
+
+
+/**
+ * Get the size of an event from a table
+ *
+ * @rceb: pointer to the buffer with the event
+ * @rceb_size: size of the area pointed to by @rceb in bytes.
+ * @returns: > 0      Size of the event
+ *          -ENOSPC  An area big enough was not provided to look
+ *                   ahead into the event's guts and guess the size.
+ *          -EINVAL  Unknown event code (wEvent).
+ *
+ * This will look at the received RCEB and guess what is the total
+ * size. For variable sized events, it will look further ahead into
+ * their length field to see how much data should be read.
+ *
+ * Note this size is *not* final--the neh (Notification/Event Handle)
+ * might specificy an extra size to add.
+ */
+static
+ssize_t uwb_est_get_size(struct uwb_rc *uwb_rc, struct uwb_est *est,
+                        u8 event_low, const struct uwb_rceb *rceb,
+                        size_t rceb_size)
+{
+       unsigned offset;
+       ssize_t size;
+       struct device *dev = &uwb_rc->uwb_dev.dev;
+       const struct uwb_est_entry *entry;
+
+       size = -ENOENT;
+       if (event_low >= est->entries) {        /* in range? */
+               dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u out of range\n",
+                       est, est->type_event_high, est->vendor, est->product,
+                       est->entries, event_low);
+               goto out;
+       }
+       size = -ENOENT;
+       entry = &est->entry[event_low];
+       if (entry->size == 0 && entry->offset == 0) {   /* unknown? */
+               dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u unknown\n",
+                       est, est->type_event_high, est->vendor, est->product,
+                       est->entries, event_low);
+               goto out;
+       }
+       offset = entry->offset; /* extra fries with that? */
+       if (offset == 0)
+               size = entry->size;
+       else {
+               /* Ops, got an extra size field at 'offset'--read it */
+               const void *ptr = rceb;
+               size_t type_size = 0;
+               offset--;
+               size = -ENOSPC;                 /* enough data for more? */
+               switch (entry->type) {
+               case UWB_EST_16:  type_size = sizeof(__le16); break;
+               case UWB_EST_8:   type_size = sizeof(u8);     break;
+               default:         BUG();
+               }
+               if (offset + type_size > rceb_size) {
+                       dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: "
+                               "not enough data to read extra size\n",
+                               est, est->type_event_high, est->vendor,
+                               est->product, est->entries);
+                       goto out;
+               }
+               size = entry->size;
+               ptr += offset;
+               switch (entry->type) {
+               case UWB_EST_16:  size += le16_to_cpu(*(__le16 *)ptr); break;
+               case UWB_EST_8:   size += *(u8 *)ptr;                  break;
+               default:         BUG();
+               }
+       }
+out:
+       return size;
+}
+
+
+/**
+ * Guesses the size of a WA event
+ *
+ * @rceb: pointer to the buffer with the event
+ * @rceb_size: size of the area pointed to by @rceb in bytes.
+ * @returns: > 0      Size of the event
+ *          -ENOSPC  An area big enough was not provided to look
+ *                   ahead into the event's guts and guess the size.
+ *          -EINVAL  Unknown event code (wEvent).
+ *
+ * This will look at the received RCEB and guess what is the total
+ * size by checking all the tables registered with
+ * uwb_est_register(). For variable sized events, it will look further
+ * ahead into their length field to see how much data should be read.
+ *
+ * Note this size is *not* final--the neh (Notification/Event Handle)
+ * might specificy an extra size to add or replace.
+ */
+ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
+                         size_t rceb_size)
+{
+       /* FIXME: add vendor/product data */
+       ssize_t size;
+       struct device *dev = &rc->uwb_dev.dev;
+       unsigned long flags;
+       unsigned itr;
+       u16 type_event_high, event;
+
+       read_lock_irqsave(&uwb_est_lock, flags);
+       size = -ENOSPC;
+       if (rceb_size < sizeof(*rceb))
+               goto out;
+       event = le16_to_cpu(rceb->wEvent);
+       type_event_high = rceb->bEventType << 8 | (event & 0xff00) >> 8;
+       for (itr = 0; itr < uwb_est_used; itr++) {
+               if (uwb_est[itr].type_event_high != type_event_high)
+                       continue;
+               size = uwb_est_get_size(rc, &uwb_est[itr],
+                                       event & 0x00ff, rceb, rceb_size);
+               /* try more tables that might handle the same type */
+               if (size != -ENOENT)
+                       goto out;
+       }
+       dev_dbg(dev,
+               "event 0x%02x/%04x/%02x: no handlers available; RCEB %4ph\n",
+               (unsigned) rceb->bEventType,
+               (unsigned) le16_to_cpu(rceb->wEvent),
+               (unsigned) rceb->bEventContext,
+               rceb);
+       size = -ENOENT;
+out:
+       read_unlock_irqrestore(&uwb_est_lock, flags);
+       return size;
+}
+EXPORT_SYMBOL_GPL(uwb_est_find_size);
diff --git a/drivers/staging/uwb/hwa-rc.c b/drivers/staging/uwb/hwa-rc.c
new file mode 100644 (file)
index 0000000..b6effad
--- /dev/null
@@ -0,0 +1,929 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * WUSB Host Wire Adapter: Radio Control Interface (WUSB[8.6])
+ * Radio Control command/event transport
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Initialize the Radio Control interface Driver.
+ *
+ * For each device probed, creates an 'struct hwarc' which contains
+ * just the representation of the UWB Radio Controller, and the logic
+ * for reading notifications and passing them to the UWB Core.
+ *
+ * So we initialize all of those, register the UWB Radio Controller
+ * and setup the notification/event handle to pipe the notifications
+ * to the UWB management Daemon.
+ *
+ * Command and event filtering.
+ *
+ * This is the driver for the Radio Control Interface described in WUSB
+ * 1.0. The core UWB module assumes that all drivers are compliant to the
+ * WHCI 0.95 specification. We thus create a filter that parses all
+ * incoming messages from the (WUSB 1.0) device and manipulate them to
+ * conform to the WHCI 0.95 specification. Similarly, outgoing messages
+ * are parsed and manipulated to conform to the WUSB 1.0 compliant messages
+ * that the device expects. Only a few messages are affected:
+ * Affected events:
+ *    UWB_RC_EVT_BEACON
+ *    UWB_RC_EVT_BP_SLOT_CHANGE
+ *    UWB_RC_EVT_DRP_AVAIL
+ *    UWB_RC_EVT_DRP
+ * Affected commands:
+ *    UWB_RC_CMD_SCAN
+ *    UWB_RC_CMD_SET_DRP_IE
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include "../wusbcore/include/wusb.h"
+#include "../wusbcore/include/wusb-wa.h"
+#include "uwb.h"
+
+#include "uwb-internal.h"
+
+/* The device uses commands and events from the WHCI specification, although
+ * reporting itself as WUSB compliant. */
+#define WUSB_QUIRK_WHCI_CMD_EVT                0x01
+
+/**
+ * Descriptor for an instance of the UWB Radio Control Driver that
+ * attaches to the RCI interface of the Host Wired Adapter.
+ *
+ * Unless there is a lock specific to the 'data members', all access
+ * is protected by uwb_rc->mutex.
+ *
+ * The NEEP (Notification/Event EndPoint) URB (@neep_urb) writes to
+ * @rd_buffer. Note there is no locking because it is perfectly (heh!)
+ * serialized--probe() submits an URB, callback is called, processes
+ * the data (synchronously), submits another URB, and so on. There is
+ * no concurrent access to the buffer.
+ */
+struct hwarc {
+       struct usb_device *usb_dev;
+       struct usb_interface *usb_iface;
+       struct uwb_rc *uwb_rc;          /* UWB host controller */
+       struct urb *neep_urb;           /* Notification endpoint handling */
+       struct edc neep_edc;
+       void *rd_buffer;                /* NEEP read buffer */
+};
+
+
+/* Beacon received notification (WUSB 1.0 [8.6.3.2]) */
+struct uwb_rc_evt_beacon_WUSB_0100 {
+       struct uwb_rceb rceb;
+       u8      bChannelNumber;
+       __le16  wBPSTOffset;
+       u8      bLQI;
+       u8      bRSSI;
+       __le16  wBeaconInfoLength;
+       u8      BeaconInfo[];
+} __attribute__((packed));
+
+/**
+ * Filter WUSB 1.0 BEACON RCV notification to be WHCI 0.95
+ *
+ * @header: the incoming event
+ * @buf_size: size of buffer containing incoming event
+ * @new_size: size of event after filtering completed
+ *
+ * The WHCI 0.95 spec has a "Beacon Type" field. This value is unknown at
+ * the time we receive the beacon from WUSB so we just set it to
+ * UWB_RC_BEACON_TYPE_NEIGHBOR as a default.
+ * The solution below allocates memory upon receipt of every beacon from a
+ * WUSB device. This will deteriorate performance. What is the right way to
+ * do this?
+ */
+static
+int hwarc_filter_evt_beacon_WUSB_0100(struct uwb_rc *rc,
+                                     struct uwb_rceb **header,
+                                     const size_t buf_size,
+                                     size_t *new_size)
+{
+       struct uwb_rc_evt_beacon_WUSB_0100 *be;
+       struct uwb_rc_evt_beacon *newbe;
+       size_t bytes_left, ielength;
+       struct device *dev = &rc->uwb_dev.dev;
+
+       be = container_of(*header, struct uwb_rc_evt_beacon_WUSB_0100, rceb);
+       bytes_left = buf_size;
+       if (bytes_left < sizeof(*be)) {
+               dev_err(dev, "Beacon Received Notification: Not enough data "
+                       "to decode for filtering (%zu vs %zu bytes needed)\n",
+                       bytes_left, sizeof(*be));
+               return -EINVAL;
+       }
+       bytes_left -= sizeof(*be);
+       ielength = le16_to_cpu(be->wBeaconInfoLength);
+       if (bytes_left < ielength) {
+               dev_err(dev, "Beacon Received Notification: Not enough data "
+                       "to decode IEs (%zu vs %zu bytes needed)\n",
+                       bytes_left, ielength);
+               return -EINVAL;
+       }
+       newbe = kzalloc(sizeof(*newbe) + ielength, GFP_ATOMIC);
+       if (newbe == NULL)
+               return -ENOMEM;
+       newbe->rceb = be->rceb;
+       newbe->bChannelNumber = be->bChannelNumber;
+       newbe->bBeaconType = UWB_RC_BEACON_TYPE_NEIGHBOR;
+       newbe->wBPSTOffset = be->wBPSTOffset;
+       newbe->bLQI = be->bLQI;
+       newbe->bRSSI = be->bRSSI;
+       newbe->wBeaconInfoLength = be->wBeaconInfoLength;
+       memcpy(newbe->BeaconInfo, be->BeaconInfo, ielength);
+       *header = &newbe->rceb;
+       *new_size = sizeof(*newbe) + ielength;
+       return 1;  /* calling function will free memory */
+}
+
+
+/* DRP Availability change notification (WUSB 1.0 [8.6.3.8]) */
+struct uwb_rc_evt_drp_avail_WUSB_0100 {
+       struct uwb_rceb rceb;
+       __le16 wIELength;
+       u8 IEData[];
+} __attribute__((packed));
+
+/**
+ * Filter WUSB 1.0 DRP AVAILABILITY CHANGE notification to be WHCI 0.95
+ *
+ * @header: the incoming event
+ * @buf_size: size of buffer containing incoming event
+ * @new_size: size of event after filtering completed
+ */
+static
+int hwarc_filter_evt_drp_avail_WUSB_0100(struct uwb_rc *rc,
+                                        struct uwb_rceb **header,
+                                        const size_t buf_size,
+                                        size_t *new_size)
+{
+       struct uwb_rc_evt_drp_avail_WUSB_0100 *da;
+       struct uwb_rc_evt_drp_avail *newda;
+       struct uwb_ie_hdr *ie_hdr;
+       size_t bytes_left, ielength;
+       struct device *dev = &rc->uwb_dev.dev;
+
+
+       da = container_of(*header, struct uwb_rc_evt_drp_avail_WUSB_0100, rceb);
+       bytes_left = buf_size;
+       if (bytes_left < sizeof(*da)) {
+               dev_err(dev, "Not enough data to decode DRP Avail "
+                       "Notification for filtering. Expected %zu, "
+                       "received %zu.\n", (size_t)sizeof(*da), bytes_left);
+               return -EINVAL;
+       }
+       bytes_left -= sizeof(*da);
+       ielength = le16_to_cpu(da->wIELength);
+       if (bytes_left < ielength) {
+               dev_err(dev, "DRP Avail Notification filter: IE length "
+                       "[%zu bytes] does not match actual length "
+                       "[%zu bytes].\n", ielength, bytes_left);
+               return -EINVAL;
+       }
+       if (ielength < sizeof(*ie_hdr)) {
+               dev_err(dev, "DRP Avail Notification filter: Not enough "
+                       "data to decode IE [%zu bytes, %zu needed]\n",
+                       ielength, sizeof(*ie_hdr));
+               return -EINVAL;
+       }
+       ie_hdr = (void *) da->IEData;
+       if (ie_hdr->length > 32) {
+               dev_err(dev, "DRP Availability Change event has unexpected "
+                       "length for filtering. Expected < 32 bytes, "
+                       "got %zu bytes.\n", (size_t)ie_hdr->length);
+               return -EINVAL;
+       }
+       newda = kzalloc(sizeof(*newda), GFP_ATOMIC);
+       if (newda == NULL)
+               return -ENOMEM;
+       newda->rceb = da->rceb;
+       memcpy(newda->bmp, (u8 *) ie_hdr + sizeof(*ie_hdr), ie_hdr->length);
+       *header = &newda->rceb;
+       *new_size = sizeof(*newda);
+       return 1; /* calling function will free memory */
+}
+
+
+/* DRP notification (WUSB 1.0 [8.6.3.9]) */
+struct uwb_rc_evt_drp_WUSB_0100 {
+       struct uwb_rceb rceb;
+       struct uwb_dev_addr wSrcAddr;
+       u8 bExplicit;
+       __le16 wIELength;
+       u8 IEData[];
+} __attribute__((packed));
+
+/**
+ * Filter WUSB 1.0 DRP Notification to be WHCI 0.95
+ *
+ * @header: the incoming event
+ * @buf_size: size of buffer containing incoming event
+ * @new_size: size of event after filtering completed
+ *
+ * It is hard to manage DRP reservations without having a Reason code.
+ * Unfortunately there is none in the WUSB spec. We just set the default to
+ * DRP IE RECEIVED.
+ * We do not currently use the bBeaconSlotNumber value, so we set this to
+ * zero for now.
+ */
+static
+int hwarc_filter_evt_drp_WUSB_0100(struct uwb_rc *rc,
+                                  struct uwb_rceb **header,
+                                  const size_t buf_size,
+                                  size_t *new_size)
+{
+       struct uwb_rc_evt_drp_WUSB_0100 *drpev;
+       struct uwb_rc_evt_drp *newdrpev;
+       size_t bytes_left, ielength;
+       struct device *dev = &rc->uwb_dev.dev;
+
+       drpev = container_of(*header, struct uwb_rc_evt_drp_WUSB_0100, rceb);
+       bytes_left = buf_size;
+       if (bytes_left < sizeof(*drpev)) {
+               dev_err(dev, "Not enough data to decode DRP Notification "
+                       "for filtering. Expected %zu, received %zu.\n",
+                       (size_t)sizeof(*drpev), bytes_left);
+               return -EINVAL;
+       }
+       ielength = le16_to_cpu(drpev->wIELength);
+       bytes_left -= sizeof(*drpev);
+       if (bytes_left < ielength) {
+               dev_err(dev, "DRP Notification filter: header length [%zu "
+                       "bytes] does not match actual length [%zu "
+                       "bytes].\n", ielength, bytes_left);
+               return -EINVAL;
+       }
+       newdrpev = kzalloc(sizeof(*newdrpev) + ielength, GFP_ATOMIC);
+       if (newdrpev == NULL)
+               return -ENOMEM;
+       newdrpev->rceb = drpev->rceb;
+       newdrpev->src_addr = drpev->wSrcAddr;
+       newdrpev->reason = UWB_DRP_NOTIF_DRP_IE_RCVD;
+       newdrpev->beacon_slot_number = 0;
+       newdrpev->ie_length = drpev->wIELength;
+       memcpy(newdrpev->ie_data, drpev->IEData, ielength);
+       *header = &newdrpev->rceb;
+       *new_size = sizeof(*newdrpev) + ielength;
+       return 1; /* calling function will free memory */
+}
+
+
+/* Scan Command (WUSB 1.0 [8.6.2.5]) */
+struct uwb_rc_cmd_scan_WUSB_0100 {
+       struct uwb_rccb rccb;
+       u8 bChannelNumber;
+       u8 bScanState;
+} __attribute__((packed));
+
+/**
+ * Filter WHCI 0.95 SCAN command to be WUSB 1.0 SCAN command
+ *
+ * @header:   command sent to device (compliant to WHCI 0.95)
+ * @size:     size of command sent to device
+ *
+ * We only reduce the size by two bytes because the WUSB 1.0 scan command
+ * does not have the last field (wStarttime). Also, make sure we don't send
+ * the device an unexpected scan type.
+ */
+static
+int hwarc_filter_cmd_scan_WUSB_0100(struct uwb_rc *rc,
+                                   struct uwb_rccb **header,
+                                   size_t *size)
+{
+       struct uwb_rc_cmd_scan *sc;
+
+       sc = container_of(*header, struct uwb_rc_cmd_scan, rccb);
+
+       if (sc->bScanState == UWB_SCAN_ONLY_STARTTIME)
+               sc->bScanState = UWB_SCAN_ONLY;
+       /* Don't send the last two bytes. */
+       *size -= 2;
+       return 0;
+}
+
+
+/* SET DRP IE command (WUSB 1.0 [8.6.2.7]) */
+struct uwb_rc_cmd_set_drp_ie_WUSB_0100 {
+       struct uwb_rccb rccb;
+       u8 bExplicit;
+       __le16 wIELength;
+       struct uwb_ie_drp IEData[];
+} __attribute__((packed));
+
+/**
+ * Filter WHCI 0.95 SET DRP IE command to be WUSB 1.0 SET DRP IE command
+ *
+ * @header:   command sent to device (compliant to WHCI 0.95)
+ * @size:     size of command sent to device
+ *
+ * WUSB has an extra bExplicit field - we assume always explicit
+ * negotiation so this field is set. The command expected by the device is
+ * thus larger than the one prepared by the driver so we need to
+ * reallocate memory to accommodate this.
+ * We trust the driver to send us the correct data so no checking is done
+ * on incoming data - evn though it is variable length.
+ */
+static
+int hwarc_filter_cmd_set_drp_ie_WUSB_0100(struct uwb_rc *rc,
+                                         struct uwb_rccb **header,
+                                         size_t *size)
+{
+       struct uwb_rc_cmd_set_drp_ie *orgcmd;
+       struct uwb_rc_cmd_set_drp_ie_WUSB_0100 *cmd;
+       size_t ielength;
+
+       orgcmd = container_of(*header, struct uwb_rc_cmd_set_drp_ie, rccb);
+       ielength = le16_to_cpu(orgcmd->wIELength);
+       cmd = kzalloc(sizeof(*cmd) + ielength, GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+       cmd->rccb = orgcmd->rccb;
+       cmd->bExplicit = 0;
+       cmd->wIELength = orgcmd->wIELength;
+       memcpy(cmd->IEData, orgcmd->IEData, ielength);
+       *header = &cmd->rccb;
+       *size = sizeof(*cmd) + ielength;
+       return 1; /* calling function will free memory */
+}
+
+
+/**
+ * Filter data from WHCI driver to WUSB device
+ *
+ * @header: WHCI 0.95 compliant command from driver
+ * @size:   length of command
+ *
+ * The routine managing commands to the device (uwb_rc_cmd()) will call the
+ * filtering function pointer (if it exists) before it passes any data to
+ * the device. At this time the command has been formatted according to
+ * WHCI 0.95 and is ready to be sent to the device.
+ *
+ * The filter function will be provided with the current command and its
+ * length. The function will manipulate the command if necessary and
+ * potentially reallocate memory for a command that needed more memory that
+ * the given command. If new memory was created the function will return 1
+ * to indicate to the calling function that the memory need to be freed
+ * when not needed any more. The size will contain the new length of the
+ * command.
+ * If memory has not been allocated we rely on the original mechanisms to
+ * free the memory of the command - even when we reduce the value of size.
+ */
+static
+int hwarc_filter_cmd_WUSB_0100(struct uwb_rc *rc, struct uwb_rccb **header,
+                              size_t *size)
+{
+       int result;
+       struct uwb_rccb *rccb = *header;
+       int cmd = le16_to_cpu(rccb->wCommand);
+       switch (cmd) {
+       case UWB_RC_CMD_SCAN:
+               result = hwarc_filter_cmd_scan_WUSB_0100(rc, header, size);
+               break;
+       case UWB_RC_CMD_SET_DRP_IE:
+               result = hwarc_filter_cmd_set_drp_ie_WUSB_0100(rc, header, size);
+               break;
+       default:
+               result = -ENOANO;
+               break;
+       }
+       return result;
+}
+
+
+/**
+ * Filter data from WHCI driver to WUSB device
+ *
+ * @header: WHCI 0.95 compliant command from driver
+ * @size:   length of command
+ *
+ * Filter commands based on which protocol the device supports. The WUSB
+ * errata should be the same as WHCI 0.95 so we do not filter that here -
+ * only WUSB 1.0.
+ */
+static
+int hwarc_filter_cmd(struct uwb_rc *rc, struct uwb_rccb **header,
+                    size_t *size)
+{
+       int result = -ENOANO;
+       if (rc->version == 0x0100)
+               result = hwarc_filter_cmd_WUSB_0100(rc, header, size);
+       return result;
+}
+
+
+/**
+ * Compute return value as sum of incoming value and value at given offset
+ *
+ * @rceb:      event for which we compute the size, it contains a variable
+ *            length field.
+ * @core_size: size of the "non variable" part of the event
+ * @offset:    place in event where the length of the variable part is stored
+ * @buf_size: total length of buffer in which event arrived - we need to make
+ *            sure we read the offset in memory that is still part of the event
+ */
+static
+ssize_t hwarc_get_event_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
+                            size_t core_size, size_t offset,
+                            const size_t buf_size)
+{
+       ssize_t size = -ENOSPC;
+       const void *ptr = rceb;
+       size_t type_size = sizeof(__le16);
+       struct device *dev = &rc->uwb_dev.dev;
+
+       if (offset + type_size >= buf_size) {
+               dev_err(dev, "Not enough data to read extra size of event "
+                       "0x%02x/%04x/%02x, only got %zu bytes.\n",
+                       rceb->bEventType, le16_to_cpu(rceb->wEvent),
+                       rceb->bEventContext, buf_size);
+               goto out;
+       }
+       ptr += offset;
+       size = core_size + le16_to_cpu(*(__le16 *)ptr);
+out:
+       return size;
+}
+
+
+/* Beacon slot change notification (WUSB 1.0 [8.6.3.5]) */
+struct uwb_rc_evt_bp_slot_change_WUSB_0100 {
+       struct uwb_rceb rceb;
+       u8 bSlotNumber;
+} __attribute__((packed));
+
+
+/**
+ * Filter data from WUSB device to WHCI driver
+ *
+ * @header:     incoming event
+ * @buf_size:   size of buffer in which event arrived
+ * @_event_size: actual size of event in the buffer
+ * @new_size:   size of event after filtered
+ *
+ * We don't know how the buffer is constructed - there may be more than one
+ * event in it so buffer length does not determine event length. We first
+ * determine the expected size of the incoming event. This value is passed
+ * back only if the actual filtering succeeded (so we know the computed
+ * expected size is correct). This value will be zero if
+ * the event did not need any filtering.
+ *
+ * WHCI interprets the BP Slot Change event's data differently than
+ * WUSB. The event sizes are exactly the same. The data field
+ * indicates the new beacon slot in which a RC is transmitting its
+ * beacon. The maximum value of this is 96 (wMacBPLength ECMA-368
+ * 17.16 (Table 117)). We thus know that the WUSB value will not set
+ * the bit bNoSlot, so we don't really do anything (placeholder).
+ */
+static
+int hwarc_filter_event_WUSB_0100(struct uwb_rc *rc, struct uwb_rceb **header,
+                                const size_t buf_size, size_t *_real_size,
+                                size_t *_new_size)
+{
+       int result = -ENOANO;
+       struct uwb_rceb *rceb = *header;
+       int event = le16_to_cpu(rceb->wEvent);
+       ssize_t event_size;
+       size_t core_size, offset;
+
+       if (rceb->bEventType != UWB_RC_CET_GENERAL)
+               goto out;
+       switch (event) {
+       case UWB_RC_EVT_BEACON:
+               core_size = sizeof(struct uwb_rc_evt_beacon_WUSB_0100);
+               offset = offsetof(struct uwb_rc_evt_beacon_WUSB_0100,
+                                 wBeaconInfoLength);
+               event_size = hwarc_get_event_size(rc, rceb, core_size,
+                                                 offset, buf_size);
+               if (event_size < 0)
+                       goto out;
+               *_real_size = event_size;
+               result = hwarc_filter_evt_beacon_WUSB_0100(rc, header,
+                                                          buf_size, _new_size);
+               break;
+       case UWB_RC_EVT_BP_SLOT_CHANGE:
+               *_new_size = *_real_size =
+                       sizeof(struct uwb_rc_evt_bp_slot_change_WUSB_0100);
+               result = 0;
+               break;
+
+       case UWB_RC_EVT_DRP_AVAIL:
+               core_size = sizeof(struct uwb_rc_evt_drp_avail_WUSB_0100);
+               offset = offsetof(struct uwb_rc_evt_drp_avail_WUSB_0100,
+                                 wIELength);
+               event_size = hwarc_get_event_size(rc, rceb, core_size,
+                                                 offset, buf_size);
+               if (event_size < 0)
+                       goto out;
+               *_real_size = event_size;
+               result = hwarc_filter_evt_drp_avail_WUSB_0100(
+                       rc, header, buf_size, _new_size);
+               break;
+
+       case UWB_RC_EVT_DRP:
+               core_size = sizeof(struct uwb_rc_evt_drp_WUSB_0100);
+               offset = offsetof(struct uwb_rc_evt_drp_WUSB_0100, wIELength);
+               event_size = hwarc_get_event_size(rc, rceb, core_size,
+                                                 offset, buf_size);
+               if (event_size < 0)
+                       goto out;
+               *_real_size = event_size;
+               result = hwarc_filter_evt_drp_WUSB_0100(rc, header,
+                                                       buf_size, _new_size);
+               break;
+
+       default:
+               break;
+       }
+out:
+       return result;
+}
+
+/**
+ * Filter data from WUSB device to WHCI driver
+ *
+ * @header:     incoming event
+ * @buf_size:   size of buffer in which event arrived
+ * @_event_size: actual size of event in the buffer
+ * @_new_size:  size of event after filtered
+ *
+ * Filter events based on which protocol the device supports. The WUSB
+ * errata should be the same as WHCI 0.95 so we do not filter that here -
+ * only WUSB 1.0.
+ *
+ * If we don't handle it, we return -ENOANO (why the weird error code?
+ * well, so if I get it, I can pinpoint in the code that raised
+ * it...after all, not too many places use the higher error codes).
+ */
+static
+int hwarc_filter_event(struct uwb_rc *rc, struct uwb_rceb **header,
+                      const size_t buf_size, size_t *_real_size,
+                      size_t *_new_size)
+{
+       int result = -ENOANO;
+       if (rc->version == 0x0100)
+               result =  hwarc_filter_event_WUSB_0100(
+                       rc, header, buf_size, _real_size, _new_size);
+       return result;
+}
+
+
+/**
+ * Execute an UWB RC command on HWA
+ *
+ * @rc:              Instance of a Radio Controller that is a HWA
+ * @cmd:      Buffer containing the RCCB and payload to execute
+ * @cmd_size: Size of the command buffer.
+ *
+ * NOTE: rc's mutex has to be locked
+ */
+static
+int hwarc_cmd(struct uwb_rc *uwb_rc, const struct uwb_rccb *cmd, size_t cmd_size)
+{
+       struct hwarc *hwarc = uwb_rc->priv;
+       return usb_control_msg(
+               hwarc->usb_dev, usb_sndctrlpipe(hwarc->usb_dev, 0),
+               WA_EXEC_RC_CMD, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               0, hwarc->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+               (void *) cmd, cmd_size, 100 /* FIXME: this is totally arbitrary */);
+}
+
+static
+int hwarc_reset(struct uwb_rc *uwb_rc)
+{
+       struct hwarc *hwarc = uwb_rc->priv;
+       int result;
+
+       /* device lock must be held when calling usb_reset_device. */
+       result = usb_lock_device_for_reset(hwarc->usb_dev, NULL);
+       if (result >= 0) {
+               result = usb_reset_device(hwarc->usb_dev);
+               usb_unlock_device(hwarc->usb_dev);
+       }
+
+       return result;
+}
+
+/**
+ * Callback for the notification and event endpoint
+ *
+ * Check's that everything is fine and then passes the read data to
+ * the notification/event handling mechanism (neh).
+ */
+static
+void hwarc_neep_cb(struct urb *urb)
+{
+       struct hwarc *hwarc = urb->context;
+       struct usb_interface *usb_iface = hwarc->usb_iface;
+       struct device *dev = &usb_iface->dev;
+       int result;
+
+       switch (result = urb->status) {
+       case 0:
+               uwb_rc_neh_grok(hwarc->uwb_rc, urb->transfer_buffer,
+                               urb->actual_length);
+               break;
+       case -ECONNRESET:       /* Not an error, but a controlled situation; */
+       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
+               goto out;
+       case -ESHUTDOWN:        /* going away! */
+               goto out;
+       default:                /* On general errors, retry unless it gets ugly */
+               if (edc_inc(&hwarc->neep_edc, EDC_MAX_ERRORS,
+                           EDC_ERROR_TIMEFRAME))
+                       goto error_exceeded;
+               dev_err(dev, "NEEP: URB error %d\n", urb->status);
+       }
+       result = usb_submit_urb(urb, GFP_ATOMIC);
+       if (result < 0 && result != -ENODEV && result != -EPERM) {
+               /* ignoring unrecoverable errors */
+               dev_err(dev, "NEEP: Can't resubmit URB (%d) resetting device\n",
+                       result);
+               goto error;
+       }
+out:
+       return;
+
+error_exceeded:
+       dev_err(dev, "NEEP: URB max acceptable errors "
+               "exceeded, resetting device\n");
+error:
+       uwb_rc_neh_error(hwarc->uwb_rc, result);
+       uwb_rc_reset_all(hwarc->uwb_rc);
+       return;
+}
+
+static void hwarc_init(struct hwarc *hwarc)
+{
+       edc_init(&hwarc->neep_edc);
+}
+
+/**
+ * Initialize the notification/event endpoint stuff
+ *
+ * Note this is effectively a parallel thread; it knows that
+ * hwarc->uwb_rc always exists because the existence of a 'hwarc'
+ * means that there is a reverence on the hwarc->uwb_rc (see
+ * _probe()), and thus _neep_cb() can execute safely.
+ */
+static int hwarc_neep_init(struct uwb_rc *rc)
+{
+       struct hwarc *hwarc = rc->priv;
+       struct usb_interface *iface = hwarc->usb_iface;
+       struct usb_device *usb_dev = interface_to_usbdev(iface);
+       struct device *dev = &iface->dev;
+       int result;
+       struct usb_endpoint_descriptor *epd;
+
+       epd = &iface->cur_altsetting->endpoint[0].desc;
+       hwarc->rd_buffer = (void *) __get_free_page(GFP_KERNEL);
+       if (hwarc->rd_buffer == NULL) {
+               dev_err(dev, "Unable to allocate notification's read buffer\n");
+               goto error_rd_buffer;
+       }
+       hwarc->neep_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (hwarc->neep_urb == NULL)
+               goto error_urb_alloc;
+       usb_fill_int_urb(hwarc->neep_urb, usb_dev,
+                        usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
+                        hwarc->rd_buffer, PAGE_SIZE,
+                        hwarc_neep_cb, hwarc, epd->bInterval);
+       result = usb_submit_urb(hwarc->neep_urb, GFP_ATOMIC);
+       if (result < 0) {
+               dev_err(dev, "Cannot submit notification URB: %d\n", result);
+               goto error_neep_submit;
+       }
+       return 0;
+
+error_neep_submit:
+       usb_free_urb(hwarc->neep_urb);
+       hwarc->neep_urb = NULL;
+error_urb_alloc:
+       free_page((unsigned long)hwarc->rd_buffer);
+       hwarc->rd_buffer = NULL;
+error_rd_buffer:
+       return -ENOMEM;
+}
+
+
+/** Clean up all the notification endpoint resources */
+static void hwarc_neep_release(struct uwb_rc *rc)
+{
+       struct hwarc *hwarc = rc->priv;
+
+       usb_kill_urb(hwarc->neep_urb);
+       usb_free_urb(hwarc->neep_urb);
+       hwarc->neep_urb = NULL;
+
+       free_page((unsigned long)hwarc->rd_buffer);
+       hwarc->rd_buffer = NULL;
+}
+
+/**
+ * Get the version from class-specific descriptor
+ *
+ * NOTE: this descriptor comes with the big bundled configuration
+ *      descriptor that includes the interfaces' and endpoints', so
+ *      we just look for it in the cached copy kept by the USB stack.
+ *
+ * NOTE2: We convert LE fields to CPU order.
+ */
+static int hwarc_get_version(struct uwb_rc *rc)
+{
+       int result;
+
+       struct hwarc *hwarc = rc->priv;
+       struct uwb_rc_control_intf_class_desc *descr;
+       struct device *dev = &rc->uwb_dev.dev;
+       struct usb_device *usb_dev = hwarc->usb_dev;
+       char *itr;
+       struct usb_descriptor_header *hdr;
+       size_t itr_size, actconfig_idx;
+       u16 version;
+
+       actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
+               sizeof(usb_dev->config[0]);
+       itr = usb_dev->rawdescriptors[actconfig_idx];
+       itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
+       while (itr_size >= sizeof(*hdr)) {
+               hdr = (struct usb_descriptor_header *) itr;
+               dev_dbg(dev, "Extra device descriptor: "
+                       "type %02x/%u bytes @ %zu (%zu left)\n",
+                       hdr->bDescriptorType, hdr->bLength,
+                       (itr - usb_dev->rawdescriptors[actconfig_idx]),
+                       itr_size);
+               if (hdr->bDescriptorType == USB_DT_CS_RADIO_CONTROL)
+                       goto found;
+               itr += hdr->bLength;
+               itr_size -= hdr->bLength;
+       }
+       dev_err(dev, "cannot find Radio Control Interface Class descriptor\n");
+       return -ENODEV;
+
+found:
+       result = -EINVAL;
+       if (hdr->bLength > itr_size) {  /* is it available? */
+               dev_err(dev, "incomplete Radio Control Interface Class "
+                       "descriptor (%zu bytes left, %u needed)\n",
+                       itr_size, hdr->bLength);
+               goto error;
+       }
+       if (hdr->bLength < sizeof(*descr)) {
+               dev_err(dev, "short Radio Control Interface Class "
+                       "descriptor\n");
+               goto error;
+       }
+       descr = (struct uwb_rc_control_intf_class_desc *) hdr;
+       /* Make LE fields CPU order */
+       version = __le16_to_cpu(descr->bcdRCIVersion);
+       if (version != 0x0100) {
+               dev_err(dev, "Device reports protocol version 0x%04x. We "
+                       "do not support that. \n", version);
+               result = -EINVAL;
+               goto error;
+       }
+       rc->version = version;
+       dev_dbg(dev, "Device supports WUSB protocol version 0x%04x \n", rc->version);
+       result = 0;
+error:
+       return result;
+}
+
+/*
+ * By creating a 'uwb_rc', we have a reference on it -- that reference
+ * is the one we drop when we disconnect.
+ *
+ * No need to switch altsettings; according to WUSB1.0[8.6.1.1], there
+ * is only one altsetting allowed.
+ */
+static int hwarc_probe(struct usb_interface *iface,
+                      const struct usb_device_id *id)
+{
+       int result;
+       struct uwb_rc *uwb_rc;
+       struct hwarc *hwarc;
+       struct device *dev = &iface->dev;
+
+       if (iface->cur_altsetting->desc.bNumEndpoints < 1)
+               return -ENODEV;
+       if (!usb_endpoint_xfer_int(&iface->cur_altsetting->endpoint[0].desc))
+               return -ENODEV;
+
+       result = -ENOMEM;
+       uwb_rc = uwb_rc_alloc();
+       if (uwb_rc == NULL) {
+               dev_err(dev, "unable to allocate RC instance\n");
+               goto error_rc_alloc;
+       }
+       hwarc = kzalloc(sizeof(*hwarc), GFP_KERNEL);
+       if (hwarc == NULL) {
+               dev_err(dev, "unable to allocate HWA RC instance\n");
+               goto error_alloc;
+       }
+       hwarc_init(hwarc);
+       hwarc->usb_dev = usb_get_dev(interface_to_usbdev(iface));
+       hwarc->usb_iface = usb_get_intf(iface);
+       hwarc->uwb_rc = uwb_rc;
+
+       uwb_rc->owner = THIS_MODULE;
+       uwb_rc->start = hwarc_neep_init;
+       uwb_rc->stop  = hwarc_neep_release;
+       uwb_rc->cmd   = hwarc_cmd;
+       uwb_rc->reset = hwarc_reset;
+       if (id->driver_info & WUSB_QUIRK_WHCI_CMD_EVT) {
+               uwb_rc->filter_cmd   = NULL;
+               uwb_rc->filter_event = NULL;
+       } else {
+               uwb_rc->filter_cmd   = hwarc_filter_cmd;
+               uwb_rc->filter_event = hwarc_filter_event;
+       }
+
+       result = uwb_rc_add(uwb_rc, dev, hwarc);
+       if (result < 0)
+               goto error_rc_add;
+       result = hwarc_get_version(uwb_rc);
+       if (result < 0) {
+               dev_err(dev, "cannot retrieve version of RC \n");
+               goto error_get_version;
+       }
+       usb_set_intfdata(iface, hwarc);
+       return 0;
+
+error_get_version:
+       uwb_rc_rm(uwb_rc);
+error_rc_add:
+       usb_put_intf(iface);
+       usb_put_dev(hwarc->usb_dev);
+       kfree(hwarc);
+error_alloc:
+       uwb_rc_put(uwb_rc);
+error_rc_alloc:
+       return result;
+}
+
+static void hwarc_disconnect(struct usb_interface *iface)
+{
+       struct hwarc *hwarc = usb_get_intfdata(iface);
+       struct uwb_rc *uwb_rc = hwarc->uwb_rc;
+
+       usb_set_intfdata(hwarc->usb_iface, NULL);
+       uwb_rc_rm(uwb_rc);
+       usb_put_intf(hwarc->usb_iface);
+       usb_put_dev(hwarc->usb_dev);
+       kfree(hwarc);
+       uwb_rc_put(uwb_rc);     /* when creating the device, refcount = 1 */
+}
+
+static int hwarc_pre_reset(struct usb_interface *iface)
+{
+       struct hwarc *hwarc = usb_get_intfdata(iface);
+       struct uwb_rc *uwb_rc = hwarc->uwb_rc;
+
+       uwb_rc_pre_reset(uwb_rc);
+       return 0;
+}
+
+static int hwarc_post_reset(struct usb_interface *iface)
+{
+       struct hwarc *hwarc = usb_get_intfdata(iface);
+       struct uwb_rc *uwb_rc = hwarc->uwb_rc;
+
+       return uwb_rc_post_reset(uwb_rc);
+}
+
+/** USB device ID's that we handle */
+static const struct usb_device_id hwarc_id_table[] = {
+       /* D-Link DUB-1210 */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3d02, 0xe0, 0x01, 0x02),
+         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
+       /* Intel i1480 (using firmware 1.3PA2-20070828) */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x8086, 0x0c3b, 0xe0, 0x01, 0x02),
+         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
+       /* Alereon 5310 */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x01, 0x02),
+         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
+       /* Alereon 5611 */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x01, 0x02),
+         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
+       /* Generic match for the Radio Control interface */
+       { USB_INTERFACE_INFO(0xe0, 0x01, 0x02), },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, hwarc_id_table);
+
+static struct usb_driver hwarc_driver = {
+       .name =         "hwa-rc",
+       .id_table =     hwarc_id_table,
+       .probe =        hwarc_probe,
+       .disconnect =   hwarc_disconnect,
+       .pre_reset =    hwarc_pre_reset,
+       .post_reset =   hwarc_post_reset,
+};
+
+module_usb_driver(hwarc_driver);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Host Wireless Adapter Radio Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/i1480/Makefile b/drivers/staging/uwb/i1480/Makefile
new file mode 100644 (file)
index 0000000..d26fb9b
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_UWB_I1480U)       += dfu/ i1480-est.o
diff --git a/drivers/staging/uwb/i1480/dfu/Makefile b/drivers/staging/uwb/i1480/dfu/Makefile
new file mode 100644 (file)
index 0000000..4739fda
--- /dev/null
@@ -0,0 +1,10 @@
+# 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
+
+
diff --git a/drivers/staging/uwb/i1480/dfu/dfu.c b/drivers/staging/uwb/i1480/dfu/dfu.c
new file mode 100644 (file)
index 0000000..9d51ce8
--- /dev/null
@@ -0,0 +1,198 @@
+// 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);
diff --git a/drivers/staging/uwb/i1480/dfu/i1480-dfu.h b/drivers/staging/uwb/i1480/dfu/i1480-dfu.h
new file mode 100644 (file)
index 0000000..b21d058
--- /dev/null
@@ -0,0 +1,246 @@
+/* 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__ */
diff --git a/drivers/staging/uwb/i1480/dfu/mac.c b/drivers/staging/uwb/i1480/dfu/mac.c
new file mode 100644 (file)
index 0000000..6e4d6c9
--- /dev/null
@@ -0,0 +1,496 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Wireless UWB Link 1480
+ * MAC Firmware upload implementation
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Implementation of the code for parsing the firmware file (extract
+ * the headers and binary code chunks) in the fw_*() functions. The
+ * code to upload pre and mac firmwares is the same, so it uses a
+ * common entry point in __mac_fw_upload(), which uses the i1480
+ * function pointers to push the firmware to the device.
+ */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include "../../uwb.h"
+#include "i1480-dfu.h"
+
+/*
+ * Descriptor for a continuous segment of MAC fw data
+ */
+struct fw_hdr {
+       unsigned long address;
+       size_t length;
+       const u32 *bin;
+       struct fw_hdr *next;
+};
+
+
+/* Free a chain of firmware headers */
+static
+void fw_hdrs_free(struct fw_hdr *hdr)
+{
+       struct fw_hdr *next;
+
+       while (hdr) {
+               next = hdr->next;
+               kfree(hdr);
+               hdr = next;
+       }
+}
+
+
+/* Fill a firmware header descriptor from a memory buffer */
+static
+int fw_hdr_load(struct i1480 *i1480, struct fw_hdr *hdr, unsigned hdr_cnt,
+               const char *_data, const u32 *data_itr, const u32 *data_top)
+{
+       size_t hdr_offset =  (const char *) data_itr - _data;
+       size_t remaining_size = (void *) data_top - (void *) data_itr;
+       if (data_itr + 2 > data_top) {
+               dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in header at "
+                      "offset %zu, limit %zu\n",
+                      hdr_cnt, hdr_offset,
+                      (const char *) data_itr + 2 - _data,
+                      (const char *) data_top - _data);
+               return -EINVAL;
+       }
+       hdr->next = NULL;
+       hdr->address = le32_to_cpu(*data_itr++);
+       hdr->length = le32_to_cpu(*data_itr++);
+       hdr->bin = data_itr;
+       if (hdr->length > remaining_size) {
+               dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in data; "
+                      "chunk too long (%zu bytes), only %zu left\n",
+                      hdr_cnt, hdr_offset, hdr->length, remaining_size);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+/**
+ * Get a buffer where the firmware is supposed to be and create a
+ * chain of headers linking them together.
+ *
+ * @phdr: where to place the pointer to the first header (headers link
+ *        to the next via the @hdr->next ptr); need to free the whole
+ *        chain when done.
+ *
+ * @_data: Pointer to the data buffer.
+ *
+ * @_data_size: Size of the data buffer (bytes); data size has to be a
+ *              multiple of 4. Function will fail if not.
+ *
+ * Goes over the whole binary blob; reads the first chunk and creates
+ * a fw hdr from it (which points to where the data is in @_data and
+ * the length of the chunk); then goes on to the next chunk until
+ * done. Each header is linked to the next.
+ */
+static
+int fw_hdrs_load(struct i1480 *i1480, struct fw_hdr **phdr,
+                const char *_data, size_t data_size)
+{
+       int result;
+       unsigned hdr_cnt = 0;
+       u32 *data = (u32 *) _data, *data_itr, *data_top;
+       struct fw_hdr *hdr, **prev_hdr = phdr;
+
+       result = -EINVAL;
+       /* Check size is ok and pointer is aligned */
+       if (data_size % sizeof(u32) != 0)
+               goto error;
+       if ((unsigned long) _data % sizeof(u16) != 0)
+               goto error;
+       *phdr = NULL;
+       data_itr = data;
+       data_top = (u32 *) (_data + data_size);
+       while (data_itr < data_top) {
+               result = -ENOMEM;
+               hdr = kmalloc(sizeof(*hdr), GFP_KERNEL);
+               if (hdr == NULL) {
+                       dev_err(i1480->dev, "Cannot allocate fw header "
+                              "for chunk #%u\n", hdr_cnt);
+                       goto error_alloc;
+               }
+               result = fw_hdr_load(i1480, hdr, hdr_cnt,
+                                    _data, data_itr, data_top);
+               if (result < 0)
+                       goto error_load;
+               data_itr += 2 + hdr->length;
+               *prev_hdr = hdr;
+               prev_hdr = &hdr->next;
+               hdr_cnt++;
+       };
+       *prev_hdr = NULL;
+       return 0;
+
+error_load:
+       kfree(hdr);
+error_alloc:
+       fw_hdrs_free(*phdr);
+error:
+       return result;
+}
+
+
+/**
+ * Compares a chunk of fw with one in the devices's memory
+ *
+ * @i1480:     Device instance
+ * @hdr:     Pointer to the firmware chunk
+ * @returns: 0 if equal, < 0 errno on error. If > 0, it is the offset
+ *           where the difference was found (plus one).
+ *
+ * Kind of dirty and simplistic, but does the trick in both the PCI
+ * and USB version. We do a quick[er] memcmp(), and if it fails, we do
+ * a byte-by-byte to find the offset.
+ */
+static
+ssize_t i1480_fw_cmp(struct i1480 *i1480, struct fw_hdr *hdr)
+{
+       ssize_t result = 0;
+       u32 src_itr = 0, cnt;
+       size_t size = hdr->length*sizeof(hdr->bin[0]);
+       size_t chunk_size;
+       u8 *bin = (u8 *) hdr->bin;
+
+       while (size > 0) {
+               chunk_size = size < i1480->buf_size ? size : i1480->buf_size;
+               result = i1480->read(i1480, hdr->address + src_itr, chunk_size);
+               if (result < 0) {
+                       dev_err(i1480->dev, "error reading for verification: "
+                               "%zd\n", result);
+                       goto error;
+               }
+               if (memcmp(i1480->cmd_buf, bin + src_itr, result)) {
+                       u8 *buf = i1480->cmd_buf;
+                       for (cnt = 0; cnt < result; cnt++)
+                               if (bin[src_itr + cnt] != buf[cnt]) {
+                                       dev_err(i1480->dev, "byte failed at "
+                                               "src_itr %u cnt %u [0x%02x "
+                                               "vs 0x%02x]\n", src_itr, cnt,
+                                               bin[src_itr + cnt], buf[cnt]);
+                                       result = src_itr + cnt + 1;
+                                       goto cmp_failed;
+                               }
+               }
+               src_itr += result;
+               size -= result;
+       }
+       result = 0;
+error:
+cmp_failed:
+       return result;
+}
+
+
+/**
+ * Writes firmware headers to the device.
+ *
+ * @prd:     PRD instance
+ * @hdr:     Processed firmware
+ * @returns: 0 if ok, < 0 errno on error.
+ */
+static
+int mac_fw_hdrs_push(struct i1480 *i1480, struct fw_hdr *hdr,
+                    const char *fw_name, const char *fw_tag)
+{
+       struct device *dev = i1480->dev;
+       ssize_t result = 0;
+       struct fw_hdr *hdr_itr;
+       int verif_retry_count;
+
+       /* Now, header by header, push them to the hw */
+       for (hdr_itr = hdr; hdr_itr != NULL; hdr_itr = hdr_itr->next) {
+               verif_retry_count = 0;
+retry:
+               dev_dbg(dev, "fw chunk (%zu @ 0x%08lx)\n",
+                       hdr_itr->length * sizeof(hdr_itr->bin[0]),
+                       hdr_itr->address);
+               result = i1480->write(i1480, hdr_itr->address, hdr_itr->bin,
+                                   hdr_itr->length*sizeof(hdr_itr->bin[0]));
+               if (result < 0) {
+                       dev_err(dev, "%s fw '%s': write failed (%zuB @ 0x%lx):"
+                               " %zd\n", fw_tag, fw_name,
+                               hdr_itr->length * sizeof(hdr_itr->bin[0]),
+                               hdr_itr->address, result);
+                       break;
+               }
+               result = i1480_fw_cmp(i1480, hdr_itr);
+               if (result < 0) {
+                       dev_err(dev, "%s fw '%s': verification read "
+                               "failed (%zuB @ 0x%lx): %zd\n",
+                               fw_tag, fw_name,
+                               hdr_itr->length * sizeof(hdr_itr->bin[0]),
+                               hdr_itr->address, result);
+                       break;
+               }
+               if (result > 0) {       /* Offset where it failed + 1 */
+                       result--;
+                       dev_err(dev, "%s fw '%s': WARNING: verification "
+                               "failed at 0x%lx: retrying\n",
+                               fw_tag, fw_name, hdr_itr->address + result);
+                       if (++verif_retry_count < 3)
+                               goto retry;     /* write this block again! */
+                       dev_err(dev, "%s fw '%s': verification failed at 0x%lx: "
+                               "tried %d times\n", fw_tag, fw_name,
+                               hdr_itr->address + result, verif_retry_count);
+                       result = -EINVAL;
+                       break;
+               }
+       }
+       return result;
+}
+
+
+/** Puts the device in firmware upload mode.*/
+static
+int mac_fw_upload_enable(struct i1480 *i1480)
+{
+       int result;
+       u32 reg = 0x800000c0;
+       u32 *buffer = (u32 *)i1480->cmd_buf;
+
+       if (i1480->hw_rev > 1)
+               reg = 0x8000d0d4;
+       result = i1480->read(i1480, reg, sizeof(u32));
+       if (result < 0)
+               goto error_cmd;
+       *buffer &= ~i1480_FW_UPLOAD_MODE_MASK;
+       result = i1480->write(i1480, reg, buffer, sizeof(u32));
+       if (result < 0)
+               goto error_cmd;
+       return 0;
+error_cmd:
+       dev_err(i1480->dev, "can't enable fw upload mode: %d\n", result);
+       return result;
+}
+
+
+/** Gets the device out of firmware upload mode. */
+static
+int mac_fw_upload_disable(struct i1480 *i1480)
+{
+       int result;
+       u32 reg = 0x800000c0;
+       u32 *buffer = (u32 *)i1480->cmd_buf;
+
+       if (i1480->hw_rev > 1)
+               reg = 0x8000d0d4;
+       result = i1480->read(i1480, reg, sizeof(u32));
+       if (result < 0)
+               goto error_cmd;
+       *buffer |= i1480_FW_UPLOAD_MODE_MASK;
+       result = i1480->write(i1480, reg, buffer, sizeof(u32));
+       if (result < 0)
+               goto error_cmd;
+       return 0;
+error_cmd:
+       dev_err(i1480->dev, "can't disable fw upload mode: %d\n", result);
+       return result;
+}
+
+
+
+/**
+ * Generic function for uploading a MAC firmware.
+ *
+ * @i1480:     Device instance
+ * @fw_name: Name of firmware file to upload.
+ * @fw_tag:  Name of the firmware type (for messages)
+ *           [eg: MAC, PRE]
+ * @do_wait: Wait for device to emit initialization done message (0
+ *           for PRE fws, 1 for MAC fws).
+ * @returns: 0 if ok, < 0 errno on error.
+ */
+static
+int __mac_fw_upload(struct i1480 *i1480, const char *fw_name,
+                   const char *fw_tag)
+{
+       int result;
+       const struct firmware *fw;
+       struct fw_hdr *fw_hdrs;
+
+       result = request_firmware(&fw, fw_name, i1480->dev);
+       if (result < 0) /* Up to caller to complain on -ENOENT */
+               goto out;
+       result = fw_hdrs_load(i1480, &fw_hdrs, fw->data, fw->size);
+       if (result < 0) {
+               dev_err(i1480->dev, "%s fw '%s': failed to parse firmware "
+                       "file: %d\n", fw_tag, fw_name, result);
+               goto out_release;
+       }
+       result = mac_fw_upload_enable(i1480);
+       if (result < 0)
+               goto out_hdrs_release;
+       result = mac_fw_hdrs_push(i1480, fw_hdrs, fw_name, fw_tag);
+       mac_fw_upload_disable(i1480);
+out_hdrs_release:
+       if (result >= 0)
+               dev_info(i1480->dev, "%s fw '%s': uploaded\n", fw_tag, fw_name);
+       else
+               dev_err(i1480->dev, "%s fw '%s': failed to upload (%d), "
+                       "power cycle device\n", fw_tag, fw_name, result);
+       fw_hdrs_free(fw_hdrs);
+out_release:
+       release_firmware(fw);
+out:
+       return result;
+}
+
+
+/**
+ * Upload a pre-PHY firmware
+ *
+ */
+int i1480_pre_fw_upload(struct i1480 *i1480)
+{
+       int result;
+       result = __mac_fw_upload(i1480, i1480->pre_fw_name, "PRE");
+       if (result == 0)
+               msleep(400);
+       return result;
+}
+
+
+/**
+ * Reset a the MAC and PHY
+ *
+ * @i1480:     Device's instance
+ * @returns: 0 if ok, < 0 errno code on error
+ *
+ * We put the command on kmalloc'ed memory as some arches cannot do
+ * USB from the stack. The reply event is copied from an stage buffer,
+ * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
+ *
+ * We issue the reset to make sure the UWB controller reinits the PHY;
+ * this way we can now if the PHY init went ok.
+ */
+static
+int i1480_cmd_reset(struct i1480 *i1480)
+{
+       int result;
+       struct uwb_rccb *cmd = (void *) i1480->cmd_buf;
+       struct i1480_evt_reset {
+               struct uwb_rceb rceb;
+               u8 bResultCode;
+       } __attribute__((packed)) *reply = (void *) i1480->evt_buf;
+
+       result = -ENOMEM;
+       cmd->bCommandType = UWB_RC_CET_GENERAL;
+       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET);
+       reply->rceb.bEventType = UWB_RC_CET_GENERAL;
+       reply->rceb.wEvent = UWB_RC_CMD_RESET;
+       result = i1480_cmd(i1480, "RESET", sizeof(*cmd), sizeof(*reply));
+       if (result < 0)
+               goto out;
+       if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+               dev_err(i1480->dev, "RESET: command execution failed: %u\n",
+                       reply->bResultCode);
+               result = -EIO;
+       }
+out:
+       return result;
+
+}
+
+
+/* Wait for the MAC FW to start running */
+static
+int i1480_fw_is_running_q(struct i1480 *i1480)
+{
+       int cnt = 0;
+       int result;
+       u32 *val = (u32 *) i1480->cmd_buf;
+
+       for (cnt = 0; cnt < 10; cnt++) {
+               msleep(100);
+               result = i1480->read(i1480, 0x80080000, 4);
+               if (result < 0) {
+                       dev_err(i1480->dev, "Can't read 0x8008000: %d\n", result);
+                       goto out;
+               }
+               if (*val == 0x55555555UL)       /* fw running? cool */
+                       goto out;
+       }
+       dev_err(i1480->dev, "Timed out waiting for fw to start\n");
+       result = -ETIMEDOUT;
+out:
+       return result;
+
+}
+
+
+/**
+ * Upload MAC firmware, wait for it to start
+ *
+ * @i1480:     Device instance
+ * @fw_name: Name of the file that contains the firmware
+ *
+ * This has to be called after the pre fw has been uploaded (if
+ * there is any).
+ */
+int i1480_mac_fw_upload(struct i1480 *i1480)
+{
+       int result = 0, deprecated_name = 0;
+       struct i1480_rceb *rcebe = (void *) i1480->evt_buf;
+
+       result = __mac_fw_upload(i1480, i1480->mac_fw_name, "MAC");
+       if (result == -ENOENT) {
+               result = __mac_fw_upload(i1480, i1480->mac_fw_name_deprecate,
+                                        "MAC");
+               deprecated_name = 1;
+       }
+       if (result < 0)
+               return result;
+       if (deprecated_name == 1)
+               dev_warn(i1480->dev,
+                        "WARNING: firmware file name %s is deprecated, "
+                        "please rename to %s\n",
+                        i1480->mac_fw_name_deprecate, i1480->mac_fw_name);
+       result = i1480_fw_is_running_q(i1480);
+       if (result < 0)
+               goto error_fw_not_running;
+       result = i1480->rc_setup ? i1480->rc_setup(i1480) : 0;
+       if (result < 0) {
+               dev_err(i1480->dev, "Cannot setup after MAC fw upload: %d\n",
+                       result);
+               goto error_setup;
+       }
+       result = i1480->wait_init_done(i1480);  /* wait init'on */
+       if (result < 0) {
+               dev_err(i1480->dev, "MAC fw '%s': Initialization timed out "
+                       "(%d)\n", i1480->mac_fw_name, result);
+               goto error_init_timeout;
+       }
+       /* verify we got the right initialization done event */
+       if (i1480->evt_result != sizeof(*rcebe)) {
+               dev_err(i1480->dev, "MAC fw '%s': initialization event returns "
+                       "wrong size (%zu bytes vs %zu needed)\n",
+                       i1480->mac_fw_name, i1480->evt_result, sizeof(*rcebe));
+               goto error_size;
+       }
+       result = -EIO;
+       if (i1480_rceb_check(i1480, &rcebe->rceb, NULL, 0, i1480_CET_VS1,
+                            i1480_EVT_RM_INIT_DONE) < 0) {
+               dev_err(i1480->dev, "wrong initialization event 0x%02x/%04x/%02x "
+                       "received; expected 0x%02x/%04x/00\n",
+                       rcebe->rceb.bEventType, le16_to_cpu(rcebe->rceb.wEvent),
+                       rcebe->rceb.bEventContext, i1480_CET_VS1,
+                       i1480_EVT_RM_INIT_DONE);
+               goto error_init_timeout;
+       }
+       result = i1480_cmd_reset(i1480);
+       if (result < 0)
+               dev_err(i1480->dev, "MAC fw '%s': MBOA reset failed (%d)\n",
+                       i1480->mac_fw_name, result);
+error_fw_not_running:
+error_init_timeout:
+error_size:
+error_setup:
+       return result;
+}
diff --git a/drivers/staging/uwb/i1480/dfu/phy.c b/drivers/staging/uwb/i1480/dfu/phy.c
new file mode 100644 (file)
index 0000000..13512c7
--- /dev/null
@@ -0,0 +1,190 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Wireless UWB Link 1480
+ * PHY parameters upload
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Code for uploading the PHY parameters to the PHY through the UWB
+ * Radio Control interface.
+ *
+ * We just send the data through the MPI interface using HWA-like
+ * commands and then reset the PHY to make sure it is ok.
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include "../../../wusbcore/include/wusb.h"
+#include "i1480-dfu.h"
+
+
+/**
+ * Write a value array to an address of the MPI interface
+ *
+ * @i1480:     Device descriptor
+ * @data:      Data array to write
+ * @size:      Size of the data array
+ * @returns:   0 if ok, < 0 errno code on error.
+ *
+ * The data array is organized into pairs:
+ *
+ * ADDRESS VALUE
+ *
+ * ADDRESS is BE 16 bit unsigned, VALUE 8 bit unsigned. Size thus has
+ * to be a multiple of three.
+ */
+static
+int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size)
+{
+       int result;
+       struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf;
+       struct i1480_evt_confirm *reply = i1480->evt_buf;
+
+       BUG_ON(size > 480);
+       result = -ENOMEM;
+       cmd->rccb.bCommandType = i1480_CET_VS1;
+       cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE);
+       cmd->size = cpu_to_le16(size);
+       memcpy(cmd->data, data, size);
+       reply->rceb.bEventType = i1480_CET_VS1;
+       reply->rceb.wEvent = i1480_CMD_MPI_WRITE;
+       result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply));
+       if (result < 0)
+               goto out;
+       if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+               dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n",
+                       reply->bResultCode);
+               result = -EIO;
+       }
+out:
+       return result;
+}
+
+
+/**
+ * Read a value array to from an address of the MPI interface
+ *
+ * @i1480:     Device descriptor
+ * @data:      where to place the read array
+ * @srcaddr:   Where to read from
+ * @size:      Size of the data read array
+ * @returns:   0 if ok, < 0 errno code on error.
+ *
+ * The command data array is organized into pairs ADDR0 ADDR1..., and
+ * the returned data in ADDR0 VALUE0 ADDR1 VALUE1...
+ *
+ * We generate the command array to be a sequential read and then
+ * rearrange the result.
+ *
+ * We use the i1480->cmd_buf for the command, i1480->evt_buf for the reply.
+ *
+ * As the reply has to fit in 512 bytes (i1480->evt_buffer), the max amount
+ * of values we can read is (512 - sizeof(*reply)) / 3
+ */
+static
+int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size)
+{
+       int result;
+       struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf;
+       struct i1480_evt_mpi_read *reply = i1480->evt_buf;
+       unsigned cnt;
+
+       memset(i1480->cmd_buf, 0x69, 512);
+       memset(i1480->evt_buf, 0x69, 512);
+
+       BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3);
+       result = -ENOMEM;
+       cmd->rccb.bCommandType = i1480_CET_VS1;
+       cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ);
+       cmd->size = cpu_to_le16(3*size);
+       for (cnt = 0; cnt < size; cnt++) {
+               cmd->data[cnt].page = (srcaddr + cnt) >> 8;
+               cmd->data[cnt].offset = (srcaddr + cnt) & 0xff;
+       }
+       reply->rceb.bEventType = i1480_CET_VS1;
+       reply->rceb.wEvent = i1480_CMD_MPI_READ;
+       result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size,
+                       sizeof(*reply) + 3*size);
+       if (result < 0)
+               goto out;
+       if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
+               dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n",
+                       reply->bResultCode);
+               result = -EIO;
+               goto out;
+       }
+       for (cnt = 0; cnt < size; cnt++) {
+               if (reply->data[cnt].page != (srcaddr + cnt) >> 8)
+                       dev_err(i1480->dev, "MPI-READ: page inconsistency at "
+                               "index %u: expected 0x%02x, got 0x%02x\n", cnt,
+                               (srcaddr + cnt) >> 8, reply->data[cnt].page);
+               if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff))
+                       dev_err(i1480->dev, "MPI-READ: offset inconsistency at "
+                               "index %u: expected 0x%02x, got 0x%02x\n", cnt,
+                               (srcaddr + cnt) & 0x00ff,
+                               reply->data[cnt].offset);
+               data[cnt] = reply->data[cnt].value;
+       }
+       result = 0;
+out:
+       return result;
+}
+
+
+/**
+ * Upload a PHY firmware, wait for it to start
+ *
+ * @i1480:     Device instance
+ * @fw_name: Name of the file that contains the firmware
+ *
+ * We assume the MAC fw is up and running. This means we can use the
+ * MPI interface to write the PHY firmware. Once done, we issue an
+ * MBOA Reset, which will force the MAC to reset and reinitialize the
+ * PHY. If that works, we are ready to go.
+ *
+ * Max packet size for the MPI write is 512, so the max buffer is 480
+ * (which gives us 160 byte triads of MSB, LSB and VAL for the data).
+ */
+int i1480_phy_fw_upload(struct i1480 *i1480)
+{
+       int result;
+       const struct firmware *fw;
+       const char *data_itr, *data_top;
+       const size_t MAX_BLK_SIZE = 480;        /* 160 triads */
+       size_t data_size;
+       u8 phy_stat;
+
+       result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev);
+       if (result < 0)
+               goto out;
+       /* Loop writing data in chunks as big as possible until done. */
+       for (data_itr = fw->data, data_top = data_itr + fw->size;
+            data_itr < data_top; data_itr += MAX_BLK_SIZE) {
+               data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr));
+               result = i1480_mpi_write(i1480, data_itr, data_size);
+               if (result < 0)
+                       goto error_mpi_write;
+       }
+       /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */
+       result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1);
+       if (result < 0) {
+               dev_err(i1480->dev, "PHY: can't get status: %d\n", result);
+               goto error_mpi_status;
+       }
+       if (phy_stat != 0) {
+               result = -ENODEV;
+               dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat);
+               goto error_phy_status;
+       }
+       dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name);
+error_phy_status:
+error_mpi_status:
+error_mpi_write:
+       release_firmware(fw);
+       if (result < 0)
+               dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), "
+                       "power cycle device\n", i1480->phy_fw_name, result);
+out:
+       return result;
+}
diff --git a/drivers/staging/uwb/i1480/dfu/usb.c b/drivers/staging/uwb/i1480/dfu/usb.c
new file mode 100644 (file)
index 0000000..d41086b
--- /dev/null
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Intel Wireless UWB Link 1480
+ * USB SKU firmware upload implementation
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This driver will prepare the i1480 device to behave as a real
+ * Wireless USB HWA adaptor by uploading the firmware.
+ *
+ * When the device is connected or driver is loaded, i1480_usb_probe()
+ * is called--this will allocate and initialize the device structure,
+ * fill in the pointers to the common functions (read, write,
+ * wait_init_done and cmd for HWA command execution) and once that is
+ * done, call the common firmware uploading routine. Then clean up and
+ * return -ENODEV, as we don't attach to the device.
+ *
+ * The rest are the basic ops we implement that the fw upload code
+ * uses to do its job. All the ops in the common code are i1480->NAME,
+ * the functions are i1480_usb_NAME().
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "../../uwb.h"
+#include "../../../wusbcore/include/wusb.h"
+#include "../../../wusbcore/include/wusb-wa.h"
+#include "i1480-dfu.h"
+
+struct i1480_usb {
+       struct i1480 i1480;
+       struct usb_device *usb_dev;
+       struct usb_interface *usb_iface;
+       struct urb *neep_urb;   /* URB for reading from EP1 */
+};
+
+
+static
+void i1480_usb_init(struct i1480_usb *i1480_usb)
+{
+       i1480_init(&i1480_usb->i1480);
+}
+
+
+static
+int i1480_usb_create(struct i1480_usb *i1480_usb, struct usb_interface *iface)
+{
+       struct usb_device *usb_dev = interface_to_usbdev(iface);
+       int result = -ENOMEM;
+
+       i1480_usb->usb_dev = usb_get_dev(usb_dev);      /* bind the USB device */
+       i1480_usb->usb_iface = usb_get_intf(iface);
+       usb_set_intfdata(iface, i1480_usb);             /* Bind the driver to iface0 */
+       i1480_usb->neep_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (i1480_usb->neep_urb == NULL)
+               goto error;
+       return 0;
+
+error:
+       usb_set_intfdata(iface, NULL);
+       usb_put_intf(iface);
+       usb_put_dev(usb_dev);
+       return result;
+}
+
+
+static
+void i1480_usb_destroy(struct i1480_usb *i1480_usb)
+{
+       usb_kill_urb(i1480_usb->neep_urb);
+       usb_free_urb(i1480_usb->neep_urb);
+       usb_set_intfdata(i1480_usb->usb_iface, NULL);
+       usb_put_intf(i1480_usb->usb_iface);
+       usb_put_dev(i1480_usb->usb_dev);
+}
+
+
+/**
+ * Write a buffer to a memory address in the i1480 device
+ *
+ * @i1480:  i1480 instance
+ * @memory_address:
+ *          Address where to write the data buffer to.
+ * @buffer: Buffer to the data
+ * @size:   Size of the buffer [has to be < 512].
+ * @returns: 0 if ok, < 0 errno code on error.
+ *
+ * Data buffers to USB cannot be on the stack or in vmalloc'ed areas,
+ * so we copy it to the local i1480 buffer before proceeding. In any
+ * case, we have a max size we can send.
+ */
+static
+int i1480_usb_write(struct i1480 *i1480, u32 memory_address,
+                   const void *buffer, size_t size)
+{
+       int result = 0;
+       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+       size_t buffer_size, itr = 0;
+
+       BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */
+       while (size > 0) {
+               buffer_size = size < i1480->buf_size ? size : i1480->buf_size;
+               memcpy(i1480->cmd_buf, buffer + itr, buffer_size);
+               result = usb_control_msg(
+                       i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0),
+                       0xf0, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       memory_address, (memory_address >> 16),
+                       i1480->cmd_buf, buffer_size, 100 /* FIXME: arbitrary */);
+               if (result < 0)
+                       break;
+               itr += result;
+               memory_address += result;
+               size -= result;
+       }
+       return result;
+}
+
+
+/**
+ * Read a block [max size 512] of the device's memory to @i1480's buffer.
+ *
+ * @i1480: i1480 instance
+ * @memory_address:
+ *         Address where to read from.
+ * @size:  Size to read. Smaller than or equal to 512.
+ * @returns: >= 0 number of bytes written if ok, < 0 errno code on error.
+ *
+ * NOTE: if the memory address or block is incorrect, you might get a
+ *       stall or a different memory read. Caller has to verify the
+ *       memory address and size passed back in the @neh structure.
+ */
+static
+int i1480_usb_read(struct i1480 *i1480, u32 addr, size_t size)
+{
+       ssize_t result = 0, bytes = 0;
+       size_t itr, read_size = i1480->buf_size;
+       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+
+       BUG_ON(size > i1480->buf_size);
+       BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */
+       BUG_ON(read_size > 512);
+
+       if (addr >= 0x8000d200 && addr < 0x8000d400)    /* Yeah, HW quirk */
+               read_size = 4;
+
+       for (itr = 0; itr < size; itr += read_size) {
+               size_t itr_addr = addr + itr;
+               size_t itr_size = min(read_size, size - itr);
+               result = usb_control_msg(
+                       i1480_usb->usb_dev, usb_rcvctrlpipe(i1480_usb->usb_dev, 0),
+                       0xf0, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       itr_addr, (itr_addr >> 16),
+                       i1480->cmd_buf + itr, itr_size,
+                       100 /* FIXME: arbitrary */);
+               if (result < 0) {
+                       dev_err(i1480->dev, "%s: USB read error: %zd\n",
+                               __func__, result);
+                       goto out;
+               }
+               if (result != itr_size) {
+                       result = -EIO;
+                       dev_err(i1480->dev,
+                               "%s: partial read got only %zu bytes vs %zu expected\n",
+                               __func__, result, itr_size);
+                       goto out;
+               }
+               bytes += result;
+       }
+       result = bytes;
+out:
+       return result;
+}
+
+
+/**
+ * Callback for reads on the notification/event endpoint
+ *
+ * Just enables the completion read handler.
+ */
+static
+void i1480_usb_neep_cb(struct urb *urb)
+{
+       struct i1480 *i1480 = urb->context;
+       struct device *dev = i1480->dev;
+
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ECONNRESET:       /* Not an error, but a controlled situation; */
+       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
+               dev_dbg(dev, "NEEP: reset/noent %d\n", urb->status);
+               break;
+       case -ESHUTDOWN:        /* going away! */
+               dev_dbg(dev, "NEEP: down %d\n", urb->status);
+               break;
+       default:
+               dev_err(dev, "NEEP: unknown status %d\n", urb->status);
+               break;
+       }
+       i1480->evt_result = urb->actual_length;
+       complete(&i1480->evt_complete);
+       return;
+}
+
+
+/**
+ * Wait for the MAC FW to initialize
+ *
+ * MAC FW sends a 0xfd/0101/00 notification to EP1 when done
+ * initializing. Get that notification into i1480->evt_buf; upper layer
+ * will verify it.
+ *
+ * Set i1480->evt_result with the result of getting the event or its
+ * size (if successful).
+ *
+ * Delivers the data directly to i1480->evt_buf
+ */
+static
+int i1480_usb_wait_init_done(struct i1480 *i1480)
+{
+       int result;
+       struct device *dev = i1480->dev;
+       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+       struct usb_endpoint_descriptor *epd;
+
+       init_completion(&i1480->evt_complete);
+       i1480->evt_result = -EINPROGRESS;
+       epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc;
+       usb_fill_int_urb(i1480_usb->neep_urb, i1480_usb->usb_dev,
+                        usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress),
+                        i1480->evt_buf, i1480->buf_size,
+                        i1480_usb_neep_cb, i1480, epd->bInterval);
+       result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL);
+       if (result < 0) {
+               dev_err(dev, "init done: cannot submit NEEP read: %d\n",
+                       result);
+               goto error_submit;
+       }
+       /* Wait for the USB callback to get the data */
+       result = wait_for_completion_interruptible_timeout(
+               &i1480->evt_complete, HZ);
+       if (result <= 0) {
+               result = result == 0 ? -ETIMEDOUT : result;
+               goto error_wait;
+       }
+       usb_kill_urb(i1480_usb->neep_urb);
+       return 0;
+
+error_wait:
+       usb_kill_urb(i1480_usb->neep_urb);
+error_submit:
+       i1480->evt_result = result;
+       return result;
+}
+
+
+/**
+ * Generic function for issuing commands to the i1480
+ *
+ * @i1480:      i1480 instance
+ * @cmd_name:   Name of the command (for error messages)
+ * @cmd:        Pointer to command buffer
+ * @cmd_size:   Size of the command buffer
+ * @reply:      Buffer for the reply event
+ * @reply_size: Expected size back (including RCEB); the reply buffer
+ *              is assumed to be as big as this.
+ * @returns:    >= 0 size of the returned event data if ok,
+ *              < 0 errno code on error.
+ *
+ * Arms the NE handle, issues the command to the device and checks the
+ * basics of the reply event.
+ */
+static
+int i1480_usb_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size)
+{
+       int result;
+       struct device *dev = i1480->dev;
+       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
+       struct usb_endpoint_descriptor *epd;
+       struct uwb_rccb *cmd = i1480->cmd_buf;
+       u8 iface_no;
+
+       /* Post a read on the notification & event endpoint */
+       iface_no = i1480_usb->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+       epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc;
+       usb_fill_int_urb(
+               i1480_usb->neep_urb, i1480_usb->usb_dev,
+               usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress),
+               i1480->evt_buf, i1480->buf_size,
+               i1480_usb_neep_cb, i1480, epd->bInterval);
+       result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL);
+       if (result < 0) {
+               dev_err(dev, "%s: cannot submit NEEP read: %d\n",
+                       cmd_name, result);
+               goto error_submit_ep1;
+       }
+       /* Now post the command on EP0 */
+       result = usb_control_msg(
+               i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0),
+               WA_EXEC_RC_CMD,
+               USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
+               0, iface_no,
+               cmd, cmd_size,
+               100 /* FIXME: this is totally arbitrary */);
+       if (result < 0) {
+               dev_err(dev, "%s: control request failed: %d\n",
+                       cmd_name, result);
+               goto error_submit_ep0;
+       }
+       return result;
+
+error_submit_ep0:
+       usb_kill_urb(i1480_usb->neep_urb);
+error_submit_ep1:
+       return result;
+}
+
+
+/*
+ * Probe a i1480 device for uploading firmware.
+ *
+ * We attach only to interface #0, which is the radio control interface.
+ */
+static
+int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(iface);
+       struct i1480_usb *i1480_usb;
+       struct i1480 *i1480;
+       struct device *dev = &iface->dev;
+       int result;
+
+       result = -ENODEV;
+       if (iface->cur_altsetting->desc.bInterfaceNumber != 0) {
+               dev_dbg(dev, "not attaching to iface %d\n",
+                       iface->cur_altsetting->desc.bInterfaceNumber);
+               goto error;
+       }
+       if (iface->num_altsetting > 1 &&
+                       le16_to_cpu(udev->descriptor.idProduct) == 0xbabe) {
+               /* Need altsetting #1 [HW QUIRK] or EP1 won't work */
+               result = usb_set_interface(interface_to_usbdev(iface), 0, 1);
+               if (result < 0)
+                       dev_warn(dev,
+                                "can't set altsetting 1 on iface 0: %d\n",
+                                result);
+       }
+
+       if (iface->cur_altsetting->desc.bNumEndpoints < 1)
+               return -ENODEV;
+
+       result = -ENOMEM;
+       i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL);
+       if (i1480_usb == NULL) {
+               dev_err(dev, "Unable to allocate instance\n");
+               goto error;
+       }
+       i1480_usb_init(i1480_usb);
+
+       i1480 = &i1480_usb->i1480;
+       i1480->buf_size = 512;
+       i1480->cmd_buf = kmalloc_array(2, i1480->buf_size, GFP_KERNEL);
+       if (i1480->cmd_buf == NULL) {
+               dev_err(dev, "Cannot allocate transfer buffers\n");
+               result = -ENOMEM;
+               goto error_buf_alloc;
+       }
+       i1480->evt_buf = i1480->cmd_buf + i1480->buf_size;
+
+       result = i1480_usb_create(i1480_usb, iface);
+       if (result < 0) {
+               dev_err(dev, "Cannot create instance: %d\n", result);
+               goto error_create;
+       }
+
+       /* setup the fops and upload the firmware */
+       i1480->pre_fw_name = "i1480-pre-phy-0.0.bin";
+       i1480->mac_fw_name = "i1480-usb-0.0.bin";
+       i1480->mac_fw_name_deprecate = "ptc-0.0.bin";
+       i1480->phy_fw_name = "i1480-phy-0.0.bin";
+       i1480->dev = &iface->dev;
+       i1480->write = i1480_usb_write;
+       i1480->read = i1480_usb_read;
+       i1480->rc_setup = NULL;
+       i1480->wait_init_done = i1480_usb_wait_init_done;
+       i1480->cmd = i1480_usb_cmd;
+
+       result = i1480_fw_upload(&i1480_usb->i1480);    /* the real thing */
+       if (result >= 0) {
+               usb_reset_device(i1480_usb->usb_dev);
+               result = -ENODEV;       /* we don't want to bind to the iface */
+       }
+       i1480_usb_destroy(i1480_usb);
+error_create:
+       kfree(i1480->cmd_buf);
+error_buf_alloc:
+       kfree(i1480_usb);
+error:
+       return result;
+}
+
+MODULE_FIRMWARE("i1480-pre-phy-0.0.bin");
+MODULE_FIRMWARE("i1480-usb-0.0.bin");
+MODULE_FIRMWARE("i1480-phy-0.0.bin");
+
+#define i1480_USB_DEV(v, p)                            \
+{                                                      \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE       \
+                | USB_DEVICE_ID_MATCH_DEV_INFO         \
+                | USB_DEVICE_ID_MATCH_INT_INFO,        \
+       .idVendor = (v),                                \
+       .idProduct = (p),                               \
+       .bDeviceClass = 0xff,                           \
+       .bDeviceSubClass = 0xff,                        \
+       .bDeviceProtocol = 0xff,                        \
+       .bInterfaceClass = 0xff,                        \
+       .bInterfaceSubClass = 0xff,                     \
+       .bInterfaceProtocol = 0xff,                     \
+}
+
+
+/** USB device ID's that we handle */
+static const struct usb_device_id i1480_usb_id_table[] = {
+       i1480_USB_DEV(0x8086, 0xdf3b),
+       i1480_USB_DEV(0x15a9, 0x0005),
+       i1480_USB_DEV(0x07d1, 0x3802),
+       i1480_USB_DEV(0x050d, 0x305a),
+       i1480_USB_DEV(0x3495, 0x3007),
+       {},
+};
+MODULE_DEVICE_TABLE(usb, i1480_usb_id_table);
+
+
+static struct usb_driver i1480_dfu_driver = {
+       .name =         "i1480-dfu-usb",
+       .id_table =     i1480_usb_id_table,
+       .probe =        i1480_usb_probe,
+       .disconnect =   NULL,
+};
+
+module_usb_driver(i1480_dfu_driver);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Intel Wireless UWB Link 1480 firmware uploader for USB");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/i1480/i1480-est.c b/drivers/staging/uwb/i1480/i1480-est.c
new file mode 100644 (file)
index 0000000..106e0a4
--- /dev/null
@@ -0,0 +1,85 @@
+// 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);
diff --git a/drivers/staging/uwb/ie-rcv.c b/drivers/staging/uwb/ie-rcv.c
new file mode 100644 (file)
index 0000000..51a4706
--- /dev/null
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * IE Received notification handling.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/bitmap.h>
+#include "uwb-internal.h"
+
+/*
+ * Process an incoming IE Received notification.
+ */
+int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *evt)
+{
+       int result = -EINVAL;
+       struct device *dev = &evt->rc->uwb_dev.dev;
+       struct uwb_rc_evt_ie_rcv *iercv;
+
+       /* Is there enough data to decode it? */
+       if (evt->notif.size < sizeof(*iercv)) {
+               dev_err(dev, "IE Received notification: Not enough data to "
+                       "decode (%zu vs %zu bytes needed)\n",
+                       evt->notif.size, sizeof(*iercv));
+               goto error;
+       }
+       iercv = container_of(evt->notif.rceb, struct uwb_rc_evt_ie_rcv, rceb);
+
+       dev_dbg(dev, "IE received, element ID=%d\n", iercv->IEData[0]);
+
+       if (iercv->IEData[0] == UWB_RELINQUISH_REQUEST_IE) {
+               dev_warn(dev, "unhandled Relinquish Request IE\n");
+       }
+
+       return 0;
+error:
+       return result;
+}
diff --git a/drivers/staging/uwb/ie.c b/drivers/staging/uwb/ie.c
new file mode 100644 (file)
index 0000000..b11678d
--- /dev/null
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Information Element Handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Reinette Chatre <reinette.chatre@intel.com>
+ *
+ * FIXME: docs
+ */
+
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "uwb-internal.h"
+
+/**
+ * uwb_ie_next - get the next IE in a buffer
+ * @ptr: start of the buffer containing the IE data
+ * @len: length of the buffer
+ *
+ * Both @ptr and @len are updated so subsequent calls to uwb_ie_next()
+ * will get the next IE.
+ *
+ * NULL is returned (and @ptr and @len will not be updated) if there
+ * are no more IEs in the buffer or the buffer is too short.
+ */
+struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len)
+{
+       struct uwb_ie_hdr *hdr;
+       size_t ie_len;
+
+       if (*len < sizeof(struct uwb_ie_hdr))
+               return NULL;
+
+       hdr = *ptr;
+       ie_len = sizeof(struct uwb_ie_hdr) + hdr->length;
+
+       if (*len < ie_len)
+               return NULL;
+
+       *ptr += ie_len;
+       *len -= ie_len;
+
+       return hdr;
+}
+EXPORT_SYMBOL_GPL(uwb_ie_next);
+
+/**
+ * uwb_ie_dump_hex - print IEs to a character buffer
+ * @ies: the IEs to print.
+ * @len: length of all the IEs.
+ * @buf: the destination buffer.
+ * @size: size of @buf.
+ *
+ * Returns the number of characters written.
+ */
+int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len,
+                   char *buf, size_t size)
+{
+       void *ptr;
+       const struct uwb_ie_hdr *ie;
+       int r = 0;
+       u8 *d;
+
+       ptr = (void *)ies;
+       for (;;) {
+               ie = uwb_ie_next(&ptr, &len);
+               if (!ie)
+                       break;
+
+               r += scnprintf(buf + r, size - r, "%02x %02x",
+                              (unsigned)ie->element_id,
+                              (unsigned)ie->length);
+               d = (uint8_t *)ie + sizeof(struct uwb_ie_hdr);
+               while (d != ptr && r < size)
+                       r += scnprintf(buf + r, size - r, " %02x", (unsigned)*d++);
+               if (r < size)
+                       buf[r++] = '\n';
+       };
+
+       return r;
+}
+
+/**
+ * Get the IEs that a radio controller is sending in its beacon
+ *
+ * @uwb_rc:  UWB Radio Controller
+ * @returns: Size read from the system
+ *
+ * We don't need to lock the uwb_rc's mutex because we don't modify
+ * anything. Once done with the iedata buffer, call
+ * uwb_rc_ie_release(iedata). Don't call kfree on it.
+ */
+static
+ssize_t uwb_rc_get_ie(struct uwb_rc *uwb_rc, struct uwb_rc_evt_get_ie **pget_ie)
+{
+       ssize_t result;
+       struct device *dev = &uwb_rc->uwb_dev.dev;
+       struct uwb_rccb *cmd = NULL;
+       struct uwb_rceb *reply = NULL;
+       struct uwb_rc_evt_get_ie *get_ie;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->bCommandType = UWB_RC_CET_GENERAL;
+       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_GET_IE);
+       result = uwb_rc_vcmd(uwb_rc, "GET_IE", cmd, sizeof(*cmd),
+                            UWB_RC_CET_GENERAL, UWB_RC_CMD_GET_IE,
+                            &reply);
+       kfree(cmd);
+       if (result < 0)
+               return result;
+
+       get_ie = container_of(reply, struct uwb_rc_evt_get_ie, rceb);
+       if (result < sizeof(*get_ie)) {
+               dev_err(dev, "not enough data returned for decoding GET IE "
+                       "(%zu bytes received vs %zu needed)\n",
+                       result, sizeof(*get_ie));
+               return -EINVAL;
+       } else if (result < sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)) {
+               dev_err(dev, "not enough data returned for decoding GET IE "
+                       "payload (%zu bytes received vs %zu needed)\n", result,
+                       sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength));
+               return -EINVAL;
+       }
+
+       *pget_ie = get_ie;
+       return result;
+}
+
+
+/**
+ * Replace all IEs currently being transmitted by a device
+ *
+ * @cmd:    pointer to the SET-IE command with the IEs to set
+ * @size:   size of @buf
+ */
+int uwb_rc_set_ie(struct uwb_rc *rc, struct uwb_rc_cmd_set_ie *cmd)
+{
+       int result;
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_rc_evt_set_ie reply;
+
+       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+       reply.rceb.wEvent = UWB_RC_CMD_SET_IE;
+       result = uwb_rc_cmd(rc, "SET-IE", &cmd->rccb,
+                           sizeof(*cmd) + le16_to_cpu(cmd->wIELength),
+                           &reply.rceb, sizeof(reply));
+       if (result < 0)
+               goto error_cmd;
+       else if (result != sizeof(reply)) {
+               dev_err(dev, "SET-IE: not enough data to decode reply "
+                       "(%d bytes received vs %zu needed)\n",
+                       result, sizeof(reply));
+               result = -EIO;
+       } else if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+               dev_err(dev, "SET-IE: command execution failed: %s (%d)\n",
+                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+               result = -EIO;
+       } else
+               result = 0;
+error_cmd:
+       return result;
+}
+
+/* Cleanup the whole IE management subsystem */
+void uwb_rc_ie_init(struct uwb_rc *uwb_rc)
+{
+       mutex_init(&uwb_rc->ies_mutex);
+}
+
+
+/**
+ * uwb_rc_ie_setup - setup a radio controller's IE manager
+ * @uwb_rc: the radio controller.
+ *
+ * The current set of IEs are obtained from the hardware with a GET-IE
+ * command (since the radio controller is not yet beaconing this will
+ * be just the hardware's MAC and PHY Capability IEs).
+ *
+ * Returns 0 on success; -ve on an error.
+ */
+int uwb_rc_ie_setup(struct uwb_rc *uwb_rc)
+{
+       struct uwb_rc_evt_get_ie *ie_info = NULL;
+       int capacity;
+
+       capacity = uwb_rc_get_ie(uwb_rc, &ie_info);
+       if (capacity < 0)
+               return capacity;
+
+       mutex_lock(&uwb_rc->ies_mutex);
+
+       uwb_rc->ies = (struct uwb_rc_cmd_set_ie *)ie_info;
+       uwb_rc->ies->rccb.bCommandType = UWB_RC_CET_GENERAL;
+       uwb_rc->ies->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_IE);
+       uwb_rc->ies_capacity = capacity;
+
+       mutex_unlock(&uwb_rc->ies_mutex);
+
+       return 0;
+}
+
+
+/* Cleanup the whole IE management subsystem */
+void uwb_rc_ie_release(struct uwb_rc *uwb_rc)
+{
+       kfree(uwb_rc->ies);
+       uwb_rc->ies = NULL;
+       uwb_rc->ies_capacity = 0;
+}
+
+
+static int uwb_rc_ie_add_one(struct uwb_rc *rc, const struct uwb_ie_hdr *new_ie)
+{
+       struct uwb_rc_cmd_set_ie *new_ies;
+       void *ptr, *prev_ie;
+       struct uwb_ie_hdr *ie;
+       size_t length, new_ie_len, new_capacity, size, prev_size;
+
+       length = le16_to_cpu(rc->ies->wIELength);
+       new_ie_len = sizeof(struct uwb_ie_hdr) + new_ie->length;
+       new_capacity = sizeof(struct uwb_rc_cmd_set_ie) + length + new_ie_len;
+
+       if (new_capacity > rc->ies_capacity) {
+               new_ies = krealloc(rc->ies, new_capacity, GFP_KERNEL);
+               if (!new_ies)
+                       return -ENOMEM;
+               rc->ies = new_ies;
+       }
+
+       ptr = rc->ies->IEData;
+       size = length;
+       for (;;) {
+               prev_ie = ptr;
+               prev_size = size;
+               ie = uwb_ie_next(&ptr, &size);
+               if (!ie || ie->element_id > new_ie->element_id)
+                       break;
+       }
+
+       memmove(prev_ie + new_ie_len, prev_ie, prev_size);
+       memcpy(prev_ie, new_ie, new_ie_len);
+       rc->ies->wIELength = cpu_to_le16(length + new_ie_len);
+
+       return 0;
+}
+
+/**
+ * uwb_rc_ie_add - add new IEs to the radio controller's beacon
+ * @uwb_rc: the radio controller.
+ * @ies: the buffer containing the new IE or IEs to be added to
+ *       the device's beacon.
+ * @size: length of all the IEs.
+ *
+ * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
+ * after the device sent the first beacon that includes the IEs specified
+ * in the SET IE command. We thus cannot send this command if the device is
+ * not beaconing. Instead, a SET IE command will be sent later right after
+ * we start beaconing.
+ *
+ * Setting an IE on the device will overwrite all current IEs in device. So
+ * we take the current IEs being transmitted by the device, insert the
+ * new one, and call SET IE with all the IEs needed.
+ *
+ * Returns 0 on success; or -ENOMEM.
+ */
+int uwb_rc_ie_add(struct uwb_rc *uwb_rc,
+                 const struct uwb_ie_hdr *ies, size_t size)
+{
+       int result = 0;
+       void *ptr;
+       const struct uwb_ie_hdr *ie;
+
+       mutex_lock(&uwb_rc->ies_mutex);
+
+       ptr = (void *)ies;
+       for (;;) {
+               ie = uwb_ie_next(&ptr, &size);
+               if (!ie)
+                       break;
+
+               result = uwb_rc_ie_add_one(uwb_rc, ie);
+               if (result < 0)
+                       break;
+       }
+       if (result >= 0) {
+               if (size == 0) {
+                       if (uwb_rc->beaconing != -1)
+                               result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies);
+               } else
+                       result = -EINVAL;
+       }
+
+       mutex_unlock(&uwb_rc->ies_mutex);
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_ie_add);
+
+
+/*
+ * Remove an IE from internal cache
+ *
+ * We are dealing with our internal IE cache so no need to verify that the
+ * IEs are valid (it has been done already).
+ *
+ * Should be called with ies_mutex held
+ *
+ * We do not break out once an IE is found in the cache. It is currently
+ * possible to have more than one IE with the same ID included in the
+ * beacon. We don't reallocate, we just mark the size smaller.
+ */
+static
+void uwb_rc_ie_cache_rm(struct uwb_rc *uwb_rc, enum uwb_ie to_remove)
+{
+       struct uwb_ie_hdr *ie;
+       size_t len = le16_to_cpu(uwb_rc->ies->wIELength);
+       void *ptr;
+       size_t size;
+
+       ptr = uwb_rc->ies->IEData;
+       size = len;
+       for (;;) {
+               ie = uwb_ie_next(&ptr, &size);
+               if (!ie)
+                       break;
+               if (ie->element_id == to_remove) {
+                       len -= sizeof(struct uwb_ie_hdr) + ie->length;
+                       memmove(ie, ptr, size);
+                       ptr = ie;
+               }
+       }
+       uwb_rc->ies->wIELength = cpu_to_le16(len);
+}
+
+
+/**
+ * uwb_rc_ie_rm - remove an IE from the radio controller's beacon
+ * @uwb_rc: the radio controller.
+ * @element_id: the element ID of the IE to remove.
+ *
+ * Only IEs previously added with uwb_rc_ie_add() may be removed.
+ *
+ * Returns 0 on success; or -ve the SET-IE command to the radio
+ * controller failed.
+ */
+int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id)
+{
+       int result = 0;
+
+       mutex_lock(&uwb_rc->ies_mutex);
+
+       uwb_rc_ie_cache_rm(uwb_rc, element_id);
+
+       if (uwb_rc->beaconing != -1)
+               result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies);
+
+       mutex_unlock(&uwb_rc->ies_mutex);
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_ie_rm);
diff --git a/drivers/staging/uwb/include/debug-cmd.h b/drivers/staging/uwb/include/debug-cmd.h
new file mode 100644 (file)
index 0000000..f97db6c
--- /dev/null
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Ultra Wide Band
+ * Debug interface commands
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#ifndef __LINUX__UWB__DEBUG_CMD_H__
+#define __LINUX__UWB__DEBUG_CMD_H__
+
+#include <linux/types.h>
+
+/*
+ * Debug interface commands
+ *
+ * UWB_DBG_CMD_RSV_ESTABLISH: Establish a new unicast reservation.
+ *
+ * UWB_DBG_CMD_RSV_TERMINATE: Terminate the Nth reservation.
+ */
+
+enum uwb_dbg_cmd_type {
+       UWB_DBG_CMD_RSV_ESTABLISH = 1,
+       UWB_DBG_CMD_RSV_TERMINATE = 2,
+       UWB_DBG_CMD_IE_ADD = 3,
+       UWB_DBG_CMD_IE_RM = 4,
+       UWB_DBG_CMD_RADIO_START = 5,
+       UWB_DBG_CMD_RADIO_STOP = 6,
+};
+
+struct uwb_dbg_cmd_rsv_establish {
+       __u8  target[6];
+       __u8  type;
+       __u16 max_mas;
+       __u16 min_mas;
+       __u8  max_interval;
+};
+
+struct uwb_dbg_cmd_rsv_terminate {
+       int index;
+};
+
+struct uwb_dbg_cmd_ie {
+       __u8 data[128];
+       int len;
+};
+
+struct uwb_dbg_cmd {
+       __u32 type;
+       union {
+               struct uwb_dbg_cmd_rsv_establish rsv_establish;
+               struct uwb_dbg_cmd_rsv_terminate rsv_terminate;
+               struct uwb_dbg_cmd_ie ie_add;
+               struct uwb_dbg_cmd_ie ie_rm;
+       };
+};
+
+#endif /* #ifndef __LINUX__UWB__DEBUG_CMD_H__ */
diff --git a/drivers/staging/uwb/include/spec.h b/drivers/staging/uwb/include/spec.h
new file mode 100644 (file)
index 0000000..5f75caf
--- /dev/null
@@ -0,0 +1,767 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Ultra Wide Band
+ * UWB Standard definitions
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * All these definitions are based on the ECMA-368 standard.
+ *
+ * Note all definitions are Little Endian in the wire, and we will
+ * convert them to host order before operating on the bitfields (that
+ * yes, we use extensively).
+ */
+
+#ifndef __LINUX__UWB_SPEC_H__
+#define __LINUX__UWB_SPEC_H__
+
+#include <linux/types.h>
+#include <linux/bitmap.h>
+#include <linux/if_ether.h>
+
+#define i1480_FW 0x00000303
+/* #define i1480_FW 0x00000302 */
+
+/**
+ * Number of Medium Access Slots in a superframe.
+ *
+ * UWB divides time in SuperFrames, each one divided in 256 pieces, or
+ * Medium Access Slots. See MBOA MAC[5.4.5] for details. The MAS is the
+ * basic bandwidth allocation unit in UWB.
+ */
+enum { UWB_NUM_MAS = 256 };
+
+/**
+ * Number of Zones in superframe.
+ *
+ * UWB divides the superframe into zones with numbering starting from BPST.
+ * See MBOA MAC[16.8.6]
+ */
+enum { UWB_NUM_ZONES = 16 };
+
+/*
+ * Number of MAS in a zone.
+ */
+#define UWB_MAS_PER_ZONE (UWB_NUM_MAS / UWB_NUM_ZONES)
+
+/*
+ * Number of MAS required before a row can be considered available.
+ */
+#define UWB_USABLE_MAS_PER_ROW (UWB_NUM_ZONES - 1)
+
+/*
+ * Number of streams per DRP reservation between a pair of devices.
+ *
+ * [ECMA-368] section 16.8.6.
+ */
+enum { UWB_NUM_STREAMS = 8 };
+
+/*
+ * mMasLength
+ *
+ * The length of a MAS in microseconds.
+ *
+ * [ECMA-368] section 17.16.
+ */
+enum { UWB_MAS_LENGTH_US = 256 };
+
+/*
+ * mBeaconSlotLength
+ *
+ * The length of the beacon slot in microseconds.
+ *
+ * [ECMA-368] section 17.16
+ */
+enum { UWB_BEACON_SLOT_LENGTH_US = 85 };
+
+/*
+ * mMaxLostBeacons
+ *
+ * The number beacons missing in consecutive superframes before a
+ * device can be considered as unreachable.
+ *
+ * [ECMA-368] section 17.16
+ */
+enum { UWB_MAX_LOST_BEACONS = 3 };
+
+/*
+ * mDRPBackOffWinMin
+ *
+ * The minimum number of superframes to wait before trying to reserve
+ * extra MAS.
+ *
+ * [ECMA-368] section 17.16
+ */
+enum { UWB_DRP_BACKOFF_WIN_MIN = 2 };
+
+/*
+ * mDRPBackOffWinMax
+ *
+ * The maximum number of superframes to wait before trying to reserve
+ * extra MAS.
+ *
+ * [ECMA-368] section 17.16
+ */
+enum { UWB_DRP_BACKOFF_WIN_MAX = 16 };
+
+/*
+ * Length of a superframe in microseconds.
+ */
+#define UWB_SUPERFRAME_LENGTH_US (UWB_MAS_LENGTH_US * UWB_NUM_MAS)
+
+/**
+ * UWB MAC address
+ *
+ * It is *imperative* that this struct is exactly 6 packed bytes (as
+ * it is also used to define headers sent down and up the wire/radio).
+ */
+struct uwb_mac_addr {
+       u8 data[ETH_ALEN];
+} __attribute__((packed));
+
+
+/**
+ * UWB device address
+ *
+ * It is *imperative* that this struct is exactly 6 packed bytes (as
+ * it is also used to define headers sent down and up the wire/radio).
+ */
+struct uwb_dev_addr {
+       u8 data[2];
+} __attribute__((packed));
+
+
+/**
+ * Types of UWB addresses
+ *
+ * Order matters (by size).
+ */
+enum uwb_addr_type {
+       UWB_ADDR_DEV = 0,
+       UWB_ADDR_MAC = 1,
+};
+
+
+/** Size of a char buffer for printing a MAC/device address */
+enum { UWB_ADDR_STRSIZE = 32 };
+
+
+/** UWB WiMedia protocol IDs. */
+enum uwb_prid {
+       UWB_PRID_WLP_RESERVED   = 0x0000,
+       UWB_PRID_WLP            = 0x0001,
+       UWB_PRID_WUSB_BOT       = 0x0010,
+       UWB_PRID_WUSB           = 0x0010,
+       UWB_PRID_WUSB_TOP       = 0x001F,
+};
+
+
+/** PHY Rate (MBOA MAC[7.8.12, Table 61]) */
+enum uwb_phy_rate {
+       UWB_PHY_RATE_53 = 0,
+       UWB_PHY_RATE_80,
+       UWB_PHY_RATE_106,
+       UWB_PHY_RATE_160,
+       UWB_PHY_RATE_200,
+       UWB_PHY_RATE_320,
+       UWB_PHY_RATE_400,
+       UWB_PHY_RATE_480,
+       UWB_PHY_RATE_INVALID
+};
+
+
+/**
+ * Different ways to scan (MBOA MAC[6.2.2, Table 8], WUSB[Table 8-78])
+ */
+enum uwb_scan_type {
+       UWB_SCAN_ONLY = 0,
+       UWB_SCAN_OUTSIDE_BP,
+       UWB_SCAN_WHILE_INACTIVE,
+       UWB_SCAN_DISABLED,
+       UWB_SCAN_ONLY_STARTTIME,
+       UWB_SCAN_TOP
+};
+
+
+/** ACK Policy types (MBOA MAC[7.2.1.3]) */
+enum uwb_ack_pol {
+       UWB_ACK_NO = 0,
+       UWB_ACK_INM = 1,
+       UWB_ACK_B = 2,
+       UWB_ACK_B_REQ = 3,
+};
+
+
+/** DRP reservation types ([ECMA-368 table 106) */
+enum uwb_drp_type {
+       UWB_DRP_TYPE_ALIEN_BP = 0,
+       UWB_DRP_TYPE_HARD,
+       UWB_DRP_TYPE_SOFT,
+       UWB_DRP_TYPE_PRIVATE,
+       UWB_DRP_TYPE_PCA,
+};
+
+
+/** DRP Reason Codes ([ECMA-368] table 107) */
+enum uwb_drp_reason {
+       UWB_DRP_REASON_ACCEPTED = 0,
+       UWB_DRP_REASON_CONFLICT,
+       UWB_DRP_REASON_PENDING,
+       UWB_DRP_REASON_DENIED,
+       UWB_DRP_REASON_MODIFIED,
+};
+
+/** Relinquish Request Reason Codes ([ECMA-368] table 113) */
+enum uwb_relinquish_req_reason {
+       UWB_RELINQUISH_REQ_REASON_NON_SPECIFIC = 0,
+       UWB_RELINQUISH_REQ_REASON_OVER_ALLOCATION,
+};
+
+/**
+ *  DRP Notification Reason Codes (WHCI 0.95 [3.1.4.9])
+ */
+enum uwb_drp_notif_reason {
+       UWB_DRP_NOTIF_DRP_IE_RCVD = 0,
+       UWB_DRP_NOTIF_CONFLICT,
+       UWB_DRP_NOTIF_TERMINATE,
+};
+
+
+/** Allocation of MAS slots in a DRP request MBOA MAC[7.8.7] */
+struct uwb_drp_alloc {
+       __le16 zone_bm;
+       __le16 mas_bm;
+} __attribute__((packed));
+
+
+/** General MAC Header format (ECMA-368[16.2]) */
+struct uwb_mac_frame_hdr {
+       __le16 Frame_Control;
+       struct uwb_dev_addr DestAddr;
+       struct uwb_dev_addr SrcAddr;
+       __le16 Sequence_Control;
+       __le16 Access_Information;
+} __attribute__((packed));
+
+
+/**
+ * uwb_beacon_frame - a beacon frame including MAC headers
+ *
+ * [ECMA] section 16.3.
+ */
+struct uwb_beacon_frame {
+       struct uwb_mac_frame_hdr hdr;
+       struct uwb_mac_addr Device_Identifier;  /* may be a NULL EUI-48 */
+       u8 Beacon_Slot_Number;
+       u8 Device_Control;
+       u8 IEData[];
+} __attribute__((packed));
+
+
+/** Information Element codes (MBOA MAC[T54]) */
+enum uwb_ie {
+       UWB_PCA_AVAILABILITY = 2,
+       UWB_IE_DRP_AVAILABILITY = 8,
+       UWB_IE_DRP = 9,
+       UWB_BP_SWITCH_IE = 11,
+       UWB_MAC_CAPABILITIES_IE = 12,
+       UWB_PHY_CAPABILITIES_IE = 13,
+       UWB_APP_SPEC_PROBE_IE = 15,
+       UWB_IDENTIFICATION_IE = 19,
+       UWB_MASTER_KEY_ID_IE = 20,
+       UWB_RELINQUISH_REQUEST_IE = 21,
+       UWB_IE_WLP = 250, /* WiMedia Logical Link Control Protocol WLP 0.99 */
+       UWB_APP_SPEC_IE = 255,
+};
+
+
+/**
+ * Header common to all Information Elements (IEs)
+ */
+struct uwb_ie_hdr {
+       u8 element_id;  /* enum uwb_ie */
+       u8 length;
+} __attribute__((packed));
+
+
+/** Dynamic Reservation Protocol IE (MBOA MAC[7.8.6]) */
+struct uwb_ie_drp {
+       struct uwb_ie_hdr       hdr;
+       __le16                  drp_control;
+       struct uwb_dev_addr     dev_addr;
+       struct uwb_drp_alloc    allocs[];
+} __attribute__((packed));
+
+static inline int uwb_ie_drp_type(struct uwb_ie_drp *ie)
+{
+       return (le16_to_cpu(ie->drp_control) >> 0) & 0x7;
+}
+
+static inline int uwb_ie_drp_stream_index(struct uwb_ie_drp *ie)
+{
+       return (le16_to_cpu(ie->drp_control) >> 3) & 0x7;
+}
+
+static inline int uwb_ie_drp_reason_code(struct uwb_ie_drp *ie)
+{
+       return (le16_to_cpu(ie->drp_control) >> 6) & 0x7;
+}
+
+static inline int uwb_ie_drp_status(struct uwb_ie_drp *ie)
+{
+       return (le16_to_cpu(ie->drp_control) >> 9) & 0x1;
+}
+
+static inline int uwb_ie_drp_owner(struct uwb_ie_drp *ie)
+{
+       return (le16_to_cpu(ie->drp_control) >> 10) & 0x1;
+}
+
+static inline int uwb_ie_drp_tiebreaker(struct uwb_ie_drp *ie)
+{
+       return (le16_to_cpu(ie->drp_control) >> 11) & 0x1;
+}
+
+static inline int uwb_ie_drp_unsafe(struct uwb_ie_drp *ie)
+{
+       return (le16_to_cpu(ie->drp_control) >> 12) & 0x1;
+}
+
+static inline void uwb_ie_drp_set_type(struct uwb_ie_drp *ie, enum uwb_drp_type type)
+{
+       u16 drp_control = le16_to_cpu(ie->drp_control);
+       drp_control = (drp_control & ~(0x7 << 0)) | (type << 0);
+       ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_stream_index(struct uwb_ie_drp *ie, int stream_index)
+{
+       u16 drp_control = le16_to_cpu(ie->drp_control);
+       drp_control = (drp_control & ~(0x7 << 3)) | (stream_index << 3);
+       ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_reason_code(struct uwb_ie_drp *ie,
+                                      enum uwb_drp_reason reason_code)
+{
+       u16 drp_control = le16_to_cpu(ie->drp_control);
+       drp_control = (ie->drp_control & ~(0x7 << 6)) | (reason_code << 6);
+       ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_status(struct uwb_ie_drp *ie, int status)
+{
+       u16 drp_control = le16_to_cpu(ie->drp_control);
+       drp_control = (drp_control & ~(0x1 << 9)) | (status << 9);
+       ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_owner(struct uwb_ie_drp *ie, int owner)
+{
+       u16 drp_control = le16_to_cpu(ie->drp_control);
+       drp_control = (drp_control & ~(0x1 << 10)) | (owner << 10);
+       ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_tiebreaker(struct uwb_ie_drp *ie, int tiebreaker)
+{
+       u16 drp_control = le16_to_cpu(ie->drp_control);
+       drp_control = (drp_control & ~(0x1 << 11)) | (tiebreaker << 11);
+       ie->drp_control = cpu_to_le16(drp_control);
+}
+
+static inline void uwb_ie_drp_set_unsafe(struct uwb_ie_drp *ie, int unsafe)
+{
+       u16 drp_control = le16_to_cpu(ie->drp_control);
+       drp_control = (drp_control & ~(0x1 << 12)) | (unsafe << 12);
+       ie->drp_control = cpu_to_le16(drp_control);
+}
+
+/** Dynamic Reservation Protocol IE (MBOA MAC[7.8.7]) */
+struct uwb_ie_drp_avail {
+       struct uwb_ie_hdr       hdr;
+       DECLARE_BITMAP(bmp, UWB_NUM_MAS);
+} __attribute__((packed));
+
+/* Relinqish Request IE ([ECMA-368] section 16.8.19). */
+struct uwb_relinquish_request_ie {
+        struct uwb_ie_hdr       hdr;
+        __le16                  relinquish_req_control;
+        struct uwb_dev_addr     dev_addr;
+        struct uwb_drp_alloc    allocs[];
+} __attribute__((packed));
+
+static inline int uwb_ie_relinquish_req_reason_code(struct uwb_relinquish_request_ie *ie)
+{
+       return (le16_to_cpu(ie->relinquish_req_control) >> 0) & 0xf;
+}
+
+static inline void uwb_ie_relinquish_req_set_reason_code(struct uwb_relinquish_request_ie *ie,
+                                                        int reason_code)
+{
+       u16 ctrl = le16_to_cpu(ie->relinquish_req_control);
+       ctrl = (ctrl & ~(0xf << 0)) | (reason_code << 0);
+       ie->relinquish_req_control = cpu_to_le16(ctrl);
+}
+
+/**
+ * The Vendor ID is set to an OUI that indicates the vendor of the device.
+ * ECMA-368 [16.8.10]
+ */
+struct uwb_vendor_id {
+       u8 data[3];
+} __attribute__((packed));
+
+/**
+ * The device type ID
+ * FIXME: clarify what this means
+ * ECMA-368 [16.8.10]
+ */
+struct uwb_device_type_id {
+       u8 data[3];
+} __attribute__((packed));
+
+
+/**
+ * UWB device information types
+ * ECMA-368 [16.8.10]
+ */
+enum uwb_dev_info_type {
+       UWB_DEV_INFO_VENDOR_ID = 0,
+       UWB_DEV_INFO_VENDOR_TYPE,
+       UWB_DEV_INFO_NAME,
+};
+
+/**
+ * UWB device information found in Identification IE
+ * ECMA-368 [16.8.10]
+ */
+struct uwb_dev_info {
+       u8 type;        /* enum uwb_dev_info_type */
+       u8 length;
+       u8 data[];
+} __attribute__((packed));
+
+/**
+ * UWB Identification IE
+ * ECMA-368 [16.8.10]
+ */
+struct uwb_identification_ie {
+       struct uwb_ie_hdr hdr;
+       struct uwb_dev_info info[];
+} __attribute__((packed));
+
+/*
+ * UWB Radio Controller
+ *
+ * These definitions are common to the Radio Control layers as
+ * exported by the WUSB1.0 HWA and WHCI interfaces.
+ */
+
+/** Radio Control Command Block (WUSB1.0[Table 8-65] and WHCI 0.95) */
+struct uwb_rccb {
+       u8 bCommandType;                /* enum hwa_cet */
+       __le16 wCommand;                /* Command code */
+       u8 bCommandContext;             /* Context ID */
+} __attribute__((packed));
+
+
+/** Radio Control Event Block (WUSB[table 8-66], WHCI 0.95) */
+struct uwb_rceb {
+       u8 bEventType;                  /* enum hwa_cet */
+       __le16 wEvent;                  /* Event code */
+       u8 bEventContext;               /* Context ID */
+} __attribute__((packed));
+
+
+enum {
+       UWB_RC_CET_GENERAL = 0,         /* General Command/Event type */
+       UWB_RC_CET_EX_TYPE_1 = 1,       /* Extended Type 1 Command/Event type */
+};
+
+/* Commands to the radio controller */
+enum uwb_rc_cmd {
+       UWB_RC_CMD_CHANNEL_CHANGE = 16,
+       UWB_RC_CMD_DEV_ADDR_MGMT = 17,  /* Device Address Management */
+       UWB_RC_CMD_GET_IE = 18,         /* GET Information Elements */
+       UWB_RC_CMD_RESET = 19,
+       UWB_RC_CMD_SCAN = 20,           /* Scan management  */
+       UWB_RC_CMD_SET_BEACON_FILTER = 21,
+       UWB_RC_CMD_SET_DRP_IE = 22,     /* Dynamic Reservation Protocol IEs */
+       UWB_RC_CMD_SET_IE = 23,         /* Information Element management */
+       UWB_RC_CMD_SET_NOTIFICATION_FILTER = 24,
+       UWB_RC_CMD_SET_TX_POWER = 25,
+       UWB_RC_CMD_SLEEP = 26,
+       UWB_RC_CMD_START_BEACON = 27,
+       UWB_RC_CMD_STOP_BEACON = 28,
+       UWB_RC_CMD_BP_MERGE = 29,
+       UWB_RC_CMD_SEND_COMMAND_FRAME = 30,
+       UWB_RC_CMD_SET_ASIE_NOTIF = 31,
+};
+
+/* Notifications from the radio controller */
+enum uwb_rc_evt {
+       UWB_RC_EVT_IE_RCV = 0,
+       UWB_RC_EVT_BEACON = 1,
+       UWB_RC_EVT_BEACON_SIZE = 2,
+       UWB_RC_EVT_BPOIE_CHANGE = 3,
+       UWB_RC_EVT_BP_SLOT_CHANGE = 4,
+       UWB_RC_EVT_BP_SWITCH_IE_RCV = 5,
+       UWB_RC_EVT_DEV_ADDR_CONFLICT = 6,
+       UWB_RC_EVT_DRP_AVAIL = 7,
+       UWB_RC_EVT_DRP = 8,
+       UWB_RC_EVT_BP_SWITCH_STATUS = 9,
+       UWB_RC_EVT_CMD_FRAME_RCV = 10,
+       UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV = 11,
+       /* Events (command responses) use the same code as the command */
+       UWB_RC_EVT_UNKNOWN_CMD_RCV = 65535,
+};
+
+enum uwb_rc_extended_type_1_cmd {
+       UWB_RC_SET_DAA_ENERGY_MASK = 32,
+       UWB_RC_SET_NOTIFICATION_FILTER_EX = 33,
+};
+
+enum uwb_rc_extended_type_1_evt {
+       UWB_RC_DAA_ENERGY_DETECTED = 0,
+};
+
+/* Radio Control Result Code. [WHCI] table 3-3. */
+enum {
+       UWB_RC_RES_SUCCESS = 0,
+       UWB_RC_RES_FAIL,
+       UWB_RC_RES_FAIL_HARDWARE,
+       UWB_RC_RES_FAIL_NO_SLOTS,
+       UWB_RC_RES_FAIL_BEACON_TOO_LARGE,
+       UWB_RC_RES_FAIL_INVALID_PARAMETER,
+       UWB_RC_RES_FAIL_UNSUPPORTED_PWR_LEVEL,
+       UWB_RC_RES_FAIL_INVALID_IE_DATA,
+       UWB_RC_RES_FAIL_BEACON_SIZE_EXCEEDED,
+       UWB_RC_RES_FAIL_CANCELLED,
+       UWB_RC_RES_FAIL_INVALID_STATE,
+       UWB_RC_RES_FAIL_INVALID_SIZE,
+       UWB_RC_RES_FAIL_ACK_NOT_RECEIVED,
+       UWB_RC_RES_FAIL_NO_MORE_ASIE_NOTIF,
+       UWB_RC_RES_FAIL_TIME_OUT = 255,
+};
+
+/* Confirm event. [WHCI] section 3.1.3.1 etc. */
+struct uwb_rc_evt_confirm {
+       struct uwb_rceb rceb;
+       u8 bResultCode;
+} __attribute__((packed));
+
+/* Device Address Management event. [WHCI] section 3.1.3.2. */
+struct uwb_rc_evt_dev_addr_mgmt {
+       struct uwb_rceb rceb;
+       u8 baAddr[ETH_ALEN];
+       u8 bResultCode;
+} __attribute__((packed));
+
+
+/* Get IE Event. [WHCI] section 3.1.3.3. */
+struct uwb_rc_evt_get_ie {
+       struct uwb_rceb rceb;
+       __le16 wIELength;
+       u8 IEData[];
+} __attribute__((packed));
+
+/* Set DRP IE Event. [WHCI] section 3.1.3.7. */
+struct uwb_rc_evt_set_drp_ie {
+       struct uwb_rceb rceb;
+       __le16 wRemainingSpace;
+       u8 bResultCode;
+} __attribute__((packed));
+
+/* Set IE Event. [WHCI] section 3.1.3.8. */
+struct uwb_rc_evt_set_ie {
+       struct uwb_rceb rceb;
+       __le16 RemainingSpace;
+       u8 bResultCode;
+} __attribute__((packed));
+
+/* Scan command. [WHCI] 3.1.3.5. */
+struct uwb_rc_cmd_scan {
+       struct uwb_rccb rccb;
+       u8 bChannelNumber;
+       u8 bScanState;
+       __le16 wStartTime;
+} __attribute__((packed));
+
+/* Set DRP IE command. [WHCI] section 3.1.3.7. */
+struct uwb_rc_cmd_set_drp_ie {
+       struct uwb_rccb rccb;
+       __le16 wIELength;
+       struct uwb_ie_drp IEData[];
+} __attribute__((packed));
+
+/* Set IE command. [WHCI] section 3.1.3.8. */
+struct uwb_rc_cmd_set_ie {
+       struct uwb_rccb rccb;
+       __le16 wIELength;
+       u8 IEData[];
+} __attribute__((packed));
+
+/* Set DAA Energy Mask event. [WHCI 0.96] section 3.1.3.17. */
+struct uwb_rc_evt_set_daa_energy_mask {
+       struct uwb_rceb rceb;
+       __le16 wLength;
+       u8 result;
+} __attribute__((packed));
+
+/* Set Notification Filter Extended event. [WHCI 0.96] section 3.1.3.18. */
+struct uwb_rc_evt_set_notification_filter_ex {
+       struct uwb_rceb rceb;
+       __le16 wLength;
+       u8 result;
+} __attribute__((packed));
+
+/* IE Received notification. [WHCI] section 3.1.4.1. */
+struct uwb_rc_evt_ie_rcv {
+       struct uwb_rceb rceb;
+       struct uwb_dev_addr SrcAddr;
+       __le16 wIELength;
+       u8 IEData[];
+} __attribute__((packed));
+
+/* Type of the received beacon. [WHCI] section 3.1.4.2. */
+enum uwb_rc_beacon_type {
+       UWB_RC_BEACON_TYPE_SCAN = 0,
+       UWB_RC_BEACON_TYPE_NEIGHBOR,
+       UWB_RC_BEACON_TYPE_OL_ALIEN,
+       UWB_RC_BEACON_TYPE_NOL_ALIEN,
+};
+
+/* Beacon received notification. [WHCI] 3.1.4.2. */
+struct uwb_rc_evt_beacon {
+       struct uwb_rceb rceb;
+       u8      bChannelNumber;
+       u8      bBeaconType;
+       __le16  wBPSTOffset;
+       u8      bLQI;
+       u8      bRSSI;
+       __le16  wBeaconInfoLength;
+       u8      BeaconInfo[];
+} __attribute__((packed));
+
+
+/* Beacon Size Change notification. [WHCI] section 3.1.4.3 */
+struct uwb_rc_evt_beacon_size {
+       struct uwb_rceb rceb;
+       __le16 wNewBeaconSize;
+} __attribute__((packed));
+
+
+/* BPOIE Change notification. [WHCI] section 3.1.4.4. */
+struct uwb_rc_evt_bpoie_change {
+       struct uwb_rceb rceb;
+       __le16 wBPOIELength;
+       u8 BPOIE[];
+} __attribute__((packed));
+
+
+/* Beacon Slot Change notification. [WHCI] section 3.1.4.5. */
+struct uwb_rc_evt_bp_slot_change {
+       struct uwb_rceb rceb;
+       u8 slot_info;
+} __attribute__((packed));
+
+static inline int uwb_rc_evt_bp_slot_change_slot_num(
+       const struct uwb_rc_evt_bp_slot_change *evt)
+{
+       return evt->slot_info & 0x7f;
+}
+
+static inline int uwb_rc_evt_bp_slot_change_no_slot(
+       const struct uwb_rc_evt_bp_slot_change *evt)
+{
+       return (evt->slot_info & 0x80) >> 7;
+}
+
+/* BP Switch IE Received notification. [WHCI] section 3.1.4.6. */
+struct uwb_rc_evt_bp_switch_ie_rcv {
+       struct uwb_rceb rceb;
+       struct uwb_dev_addr wSrcAddr;
+       __le16 wIELength;
+       u8 IEData[];
+} __attribute__((packed));
+
+/* DevAddr Conflict notification. [WHCI] section 3.1.4.7. */
+struct uwb_rc_evt_dev_addr_conflict {
+       struct uwb_rceb rceb;
+} __attribute__((packed));
+
+/* DRP notification. [WHCI] section 3.1.4.9. */
+struct uwb_rc_evt_drp {
+       struct uwb_rceb           rceb;
+       struct uwb_dev_addr       src_addr;
+       u8                        reason;
+       u8                        beacon_slot_number;
+       __le16                    ie_length;
+       u8                        ie_data[];
+} __attribute__((packed));
+
+static inline enum uwb_drp_notif_reason uwb_rc_evt_drp_reason(struct uwb_rc_evt_drp *evt)
+{
+       return evt->reason & 0x0f;
+}
+
+
+/* DRP Availability Change notification. [WHCI] section 3.1.4.8. */
+struct uwb_rc_evt_drp_avail {
+       struct uwb_rceb rceb;
+       DECLARE_BITMAP(bmp, UWB_NUM_MAS);
+} __attribute__((packed));
+
+/* BP switch status notification. [WHCI] section 3.1.4.10. */
+struct uwb_rc_evt_bp_switch_status {
+       struct uwb_rceb rceb;
+       u8 status;
+       u8 slot_offset;
+       __le16 bpst_offset;
+       u8 move_countdown;
+} __attribute__((packed));
+
+/* Command Frame Received notification. [WHCI] section 3.1.4.11. */
+struct uwb_rc_evt_cmd_frame_rcv {
+       struct uwb_rceb rceb;
+       __le16 receive_time;
+       struct uwb_dev_addr wSrcAddr;
+       struct uwb_dev_addr wDstAddr;
+       __le16 control;
+       __le16 reserved;
+       __le16 dataLength;
+       u8 data[];
+} __attribute__((packed));
+
+/* Channel Change IE Received notification. [WHCI] section 3.1.4.12. */
+struct uwb_rc_evt_channel_change_ie_rcv {
+       struct uwb_rceb rceb;
+       struct uwb_dev_addr wSrcAddr;
+       __le16 wIELength;
+       u8 IEData[];
+} __attribute__((packed));
+
+/* DAA Energy Detected notification. [WHCI 0.96] section 3.1.4.14. */
+struct uwb_rc_evt_daa_energy_detected {
+       struct uwb_rceb rceb;
+       __le16 wLength;
+       u8 bandID;
+       u8 reserved;
+       u8 toneBmp[16];
+} __attribute__((packed));
+
+
+/**
+ * Radio Control Interface Class Descriptor
+ *
+ *  WUSB 1.0 [8.6.1.2]
+ */
+struct uwb_rc_control_intf_class_desc {
+       u8 bLength;
+       u8 bDescriptorType;
+       __le16 bcdRCIVersion;
+} __attribute__((packed));
+
+#endif /* #ifndef __LINUX__UWB_SPEC_H__ */
diff --git a/drivers/staging/uwb/include/umc.h b/drivers/staging/uwb/include/umc.h
new file mode 100644 (file)
index 0000000..ddbceb3
--- /dev/null
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * UWB Multi-interface Controller support.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ *
+ * UMC (UWB Multi-interface Controller) capabilities (e.g., radio
+ * controller, host controller) are presented as devices on the "umc"
+ * bus.
+ *
+ * The radio controller is not strictly a UMC capability but it's
+ * useful to present it as such.
+ *
+ * References:
+ *
+ *   [WHCI] Wireless Host Controller Interface Specification for
+ *          Certified Wireless Universal Serial Bus, revision 0.95.
+ *
+ * How this works is kind of convoluted but simple. The whci.ko driver
+ * loads when WHCI devices are detected. These WHCI devices expose
+ * many devices in the same PCI function (they couldn't have reused
+ * functions, no), so for each PCI function that exposes these many
+ * devices, whci ceates a umc_dev [whci_probe() -> whci_add_cap()]
+ * with umc_device_create() and adds it to the bus with
+ * umc_device_register().
+ *
+ * umc_device_register() calls device_register() which will push the
+ * bus management code to load your UMC driver's somehting_probe()
+ * that you have registered for that capability code.
+ *
+ * Now when the WHCI device is removed, whci_remove() will go over
+ * each umc_dev assigned to each of the PCI function's capabilities
+ * and through whci_del_cap() call umc_device_unregister() each
+ * created umc_dev. Of course, if you are bound to the device, your
+ * driver's something_remove() will be called.
+ */
+
+#ifndef _LINUX_UWB_UMC_H_
+#define _LINUX_UWB_UMC_H_
+
+#include <linux/device.h>
+#include <linux/pci.h>
+
+/*
+ * UMC capability IDs.
+ *
+ * 0x00 is reserved so use it for the radio controller device.
+ *
+ * [WHCI] table 2-8
+ */
+#define UMC_CAP_ID_WHCI_RC      0x00 /* radio controller */
+#define UMC_CAP_ID_WHCI_WUSB_HC 0x01 /* WUSB host controller */
+
+/**
+ * struct umc_dev - UMC capability device
+ *
+ * @version:  version of the specification this capability conforms to.
+ * @cap_id:   capability ID.
+ * @bar:      PCI Bar (64 bit) where the resource lies
+ * @resource: register space resource.
+ * @irq:      interrupt line.
+ */
+struct umc_dev {
+       u16             version;
+       u8              cap_id;
+       u8              bar;
+       struct resource resource;
+       unsigned        irq;
+       struct device   dev;
+};
+
+#define to_umc_dev(d) container_of(d, struct umc_dev, dev)
+
+/**
+ * struct umc_driver - UMC capability driver
+ * @cap_id: supported capability ID.
+ * @match: driver specific capability matching function.
+ * @match_data: driver specific data for match() (e.g., a
+ * table of pci_device_id's if umc_match_pci_id() is used).
+ */
+struct umc_driver {
+       char *name;
+       u8 cap_id;
+       int (*match)(struct umc_driver *, struct umc_dev *);
+       const void *match_data;
+
+       int  (*probe)(struct umc_dev *);
+       void (*remove)(struct umc_dev *);
+       int  (*pre_reset)(struct umc_dev *);
+       int  (*post_reset)(struct umc_dev *);
+
+       struct device_driver driver;
+};
+
+#define to_umc_driver(d) container_of(d, struct umc_driver, driver)
+
+extern struct bus_type umc_bus_type;
+
+struct umc_dev *umc_device_create(struct device *parent, int n);
+int __must_check umc_device_register(struct umc_dev *umc);
+void umc_device_unregister(struct umc_dev *umc);
+
+int __must_check __umc_driver_register(struct umc_driver *umc_drv,
+                                      struct module *mod,
+                                      const char *mod_name);
+
+/**
+ * umc_driver_register - register a UMC capabiltity driver.
+ * @umc_drv:  pointer to the driver.
+ */
+#define umc_driver_register(umc_drv) \
+       __umc_driver_register(umc_drv, THIS_MODULE, KBUILD_MODNAME)
+
+void umc_driver_unregister(struct umc_driver *umc_drv);
+
+/*
+ * Utility function you can use to match (umc_driver->match) against a
+ * null-terminated array of 'struct pci_device_id' in
+ * umc_driver->match_data.
+ */
+int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc);
+
+/**
+ * umc_parent_pci_dev - return the UMC's parent PCI device or NULL if none
+ * @umc_dev: UMC device whose parent PCI device we are looking for
+ *
+ * DIRTY!!! DON'T RELY ON THIS
+ *
+ * FIXME: This is as dirty as it gets, but we need some way to check
+ * the correct type of umc_dev->parent (so that for example, we can
+ * cast to pci_dev). Casting to pci_dev is necessary because at some
+ * point we need to request resources from the device. Mapping is
+ * easily over come (ioremap and stuff are bus agnostic), but hooking
+ * up to some error handlers (such as pci error handlers) might need
+ * this.
+ *
+ * THIS might (probably will) be removed in the future, so don't count
+ * on it.
+ */
+static inline struct pci_dev *umc_parent_pci_dev(struct umc_dev *umc_dev)
+{
+       struct pci_dev *pci_dev = NULL;
+       if (dev_is_pci(umc_dev->dev.parent))
+               pci_dev = to_pci_dev(umc_dev->dev.parent);
+       return pci_dev;
+}
+
+/**
+ * umc_dev_get() - reference a UMC device.
+ * @umc_dev: Pointer to UMC device.
+ *
+ * NOTE: we are assuming in this whole scheme that the parent device
+ *       is referenced at _probe() time and unreferenced at _remove()
+ *       time by the parent's subsystem.
+ */
+static inline struct umc_dev *umc_dev_get(struct umc_dev *umc_dev)
+{
+       get_device(&umc_dev->dev);
+       return umc_dev;
+}
+
+/**
+ * umc_dev_put() - unreference a UMC device.
+ * @umc_dev: Pointer to UMC device.
+ */
+static inline void umc_dev_put(struct umc_dev *umc_dev)
+{
+       put_device(&umc_dev->dev);
+}
+
+/**
+ * umc_set_drvdata - set UMC device's driver data.
+ * @umc_dev: Pointer to UMC device.
+ * @data:    Data to set.
+ */
+static inline void umc_set_drvdata(struct umc_dev *umc_dev, void *data)
+{
+       dev_set_drvdata(&umc_dev->dev, data);
+}
+
+/**
+ * umc_get_drvdata - recover UMC device's driver data.
+ * @umc_dev: Pointer to UMC device.
+ */
+static inline void *umc_get_drvdata(struct umc_dev *umc_dev)
+{
+       return dev_get_drvdata(&umc_dev->dev);
+}
+
+int umc_controller_reset(struct umc_dev *umc);
+
+#endif /* #ifndef _LINUX_UWB_UMC_H_ */
diff --git a/drivers/staging/uwb/include/whci.h b/drivers/staging/uwb/include/whci.h
new file mode 100644 (file)
index 0000000..1a5c2cc
--- /dev/null
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Wireless Host Controller Interface for Ultra-Wide-Band and Wireless USB
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * References:
+ *   [WHCI] Wireless Host Controller Interface Specification for
+ *          Certified Wireless Universal Serial Bus, revision 0.95.
+ */
+#ifndef _LINUX_UWB_WHCI_H_
+#define _LINUX_UWB_WHCI_H_
+
+#include <linux/pci.h>
+
+/*
+ * UWB interface capability registers (offsets from UWBBASE)
+ *
+ * [WHCI] section 2.2
+ */
+#define UWBCAPINFO     0x00 /* == UWBCAPDATA(0) */
+#  define UWBCAPINFO_TO_N_CAPS(c)      (((c) >> 0)  & 0xFull)
+#define UWBCAPDATA(n)  (8*(n))
+#  define UWBCAPDATA_TO_VERSION(c)     (((c) >> 32) & 0xFFFFull)
+#  define UWBCAPDATA_TO_OFFSET(c)      (((c) >> 18) & 0x3FFFull)
+#  define UWBCAPDATA_TO_BAR(c)         (((c) >> 16) & 0x3ull)
+#  define UWBCAPDATA_TO_SIZE(c)                ((((c) >> 8) & 0xFFull) * sizeof(u32))
+#  define UWBCAPDATA_TO_CAP_ID(c)      (((c) >> 0)  & 0xFFull)
+
+/* Size of the WHCI capability data (including the RC capability) for
+   a device with n capabilities. */
+#define UWBCAPDATA_SIZE(n) (8 + 8*(n))
+
+
+/*
+ * URC registers (offsets from URCBASE)
+ *
+ * [WHCI] section 2.3
+ */
+#define URCCMD         0x00
+#  define URCCMD_RESET         (1 << 31)  /* UMC Hardware reset */
+#  define URCCMD_RS            (1 << 30)  /* Run/Stop */
+#  define URCCMD_EARV          (1 << 29)  /* Event Address Register Valid */
+#  define URCCMD_ACTIVE                (1 << 15)  /* Command is active */
+#  define URCCMD_IWR           (1 << 14)  /* Interrupt When Ready */
+#  define URCCMD_SIZE_MASK     0x00000fff /* Command size mask */
+#define URCSTS         0x04
+#  define URCSTS_EPS           (1 << 17)  /* Event Processing Status */
+#  define URCSTS_HALTED                (1 << 16)  /* RC halted */
+#  define URCSTS_HSE           (1 << 10)  /* Host System Error...fried */
+#  define URCSTS_ER            (1 <<  9)  /* Event Ready */
+#  define URCSTS_RCI           (1 <<  8)  /* Ready for Command Interrupt */
+#  define URCSTS_INT_MASK      0x00000700 /* URC interrupt sources */
+#  define URCSTS_ISI           0x000000ff /* Interrupt Source Identification */
+#define URCINTR                0x08
+#  define URCINTR_EN_ALL       0x000007ff /* Enable all interrupt sources */
+#define URCCMDADDR     0x10
+#define URCEVTADDR     0x18
+#  define URCEVTADDR_OFFSET_MASK 0xfff    /* Event pointer offset mask */
+
+
+/** Write 32 bit @value to little endian register at @addr */
+static inline
+void le_writel(u32 value, void __iomem *addr)
+{
+       iowrite32(value, addr);
+}
+
+
+/** Read from 32 bit little endian register at @addr */
+static inline
+u32 le_readl(void __iomem *addr)
+{
+       return ioread32(addr);
+}
+
+
+/** Write 64 bit @value to little endian register at @addr */
+static inline
+void le_writeq(u64 value, void __iomem *addr)
+{
+       iowrite32(value, addr);
+       iowrite32(value >> 32, addr + 4);
+}
+
+
+/** Read from 64 bit little endian register at @addr */
+static inline
+u64 le_readq(void __iomem *addr)
+{
+       u64 value;
+       value  = ioread32(addr);
+       value |= (u64)ioread32(addr + 4) << 32;
+       return value;
+}
+
+extern int whci_wait_for(struct device *dev, u32 __iomem *reg,
+                        u32 mask, u32 result,
+                        unsigned long max_ms,  const char *tag);
+
+#endif /* #ifndef _LINUX_UWB_WHCI_H_ */
diff --git a/drivers/staging/uwb/lc-dev.c b/drivers/staging/uwb/lc-dev.c
new file mode 100644 (file)
index 0000000..3e5c07f
--- /dev/null
@@ -0,0 +1,457 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Life cycle of devices
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/kdev_t.h>
+#include <linux/random.h>
+#include <linux/stat.h>
+#include "uwb-internal.h"
+
+/* We initialize addresses to 0xff (invalid, as it is bcast) */
+static inline void uwb_dev_addr_init(struct uwb_dev_addr *addr)
+{
+       memset(&addr->data, 0xff, sizeof(addr->data));
+}
+
+static inline void uwb_mac_addr_init(struct uwb_mac_addr *addr)
+{
+       memset(&addr->data, 0xff, sizeof(addr->data));
+}
+
+/*
+ * Add callback @new to be called when an event occurs in @rc.
+ */
+int uwb_notifs_register(struct uwb_rc *rc, struct uwb_notifs_handler *new)
+{
+       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+               return -ERESTARTSYS;
+       list_add(&new->list_node, &rc->notifs_chain.list);
+       mutex_unlock(&rc->notifs_chain.mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_notifs_register);
+
+/*
+ * Remove event handler (callback)
+ */
+int uwb_notifs_deregister(struct uwb_rc *rc, struct uwb_notifs_handler *entry)
+{
+       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+               return -ERESTARTSYS;
+       list_del(&entry->list_node);
+       mutex_unlock(&rc->notifs_chain.mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_notifs_deregister);
+
+/*
+ * Notify all event handlers of a given event on @rc
+ *
+ * We are called with a valid reference to the device, or NULL if the
+ * event is not for a particular event (e.g., a BG join event).
+ */
+void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event)
+{
+       struct uwb_notifs_handler *handler;
+       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
+               return;
+       if (!list_empty(&rc->notifs_chain.list)) {
+               list_for_each_entry(handler, &rc->notifs_chain.list, list_node) {
+                       handler->cb(handler->data, uwb_dev, event);
+               }
+       }
+       mutex_unlock(&rc->notifs_chain.mutex);
+}
+
+/*
+ * Release the backing device of a uwb_dev that has been dynamically allocated.
+ */
+static void uwb_dev_sys_release(struct device *dev)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+       uwb_bce_put(uwb_dev->bce);
+       memset(uwb_dev, 0x69, sizeof(*uwb_dev));
+       kfree(uwb_dev);
+}
+
+/*
+ * Initialize a UWB device instance
+ *
+ * Alloc, zero and call this function.
+ */
+void uwb_dev_init(struct uwb_dev *uwb_dev)
+{
+       mutex_init(&uwb_dev->mutex);
+       device_initialize(&uwb_dev->dev);
+       uwb_dev->dev.release = uwb_dev_sys_release;
+       uwb_dev_addr_init(&uwb_dev->dev_addr);
+       uwb_mac_addr_init(&uwb_dev->mac_addr);
+       bitmap_fill(uwb_dev->streams, UWB_NUM_GLOBAL_STREAMS);
+}
+
+static ssize_t uwb_dev_EUI_48_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       char addr[UWB_ADDR_STRSIZE];
+
+       uwb_mac_addr_print(addr, sizeof(addr), &uwb_dev->mac_addr);
+       return sprintf(buf, "%s\n", addr);
+}
+static DEVICE_ATTR(EUI_48, S_IRUGO, uwb_dev_EUI_48_show, NULL);
+
+static ssize_t uwb_dev_DevAddr_show(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       char addr[UWB_ADDR_STRSIZE];
+
+       uwb_dev_addr_print(addr, sizeof(addr), &uwb_dev->dev_addr);
+       return sprintf(buf, "%s\n", addr);
+}
+static DEVICE_ATTR(DevAddr, S_IRUGO, uwb_dev_DevAddr_show, NULL);
+
+/*
+ * Show the BPST of this device.
+ *
+ * Calculated from the receive time of the device's beacon and it's
+ * slot number.
+ */
+static ssize_t uwb_dev_BPST_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       struct uwb_beca_e *bce;
+       struct uwb_beacon_frame *bf;
+       u16 bpst;
+
+       bce = uwb_dev->bce;
+       mutex_lock(&bce->mutex);
+       bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
+       bpst = bce->be->wBPSTOffset
+               - (u16)(bf->Beacon_Slot_Number * UWB_BEACON_SLOT_LENGTH_US);
+       mutex_unlock(&bce->mutex);
+
+       return sprintf(buf, "%d\n", bpst);
+}
+static DEVICE_ATTR(BPST, S_IRUGO, uwb_dev_BPST_show, NULL);
+
+/*
+ * Show the IEs a device is beaconing
+ *
+ * We need to access the beacon cache, so we just lock it really
+ * quick, print the IEs and unlock.
+ *
+ * We have a reference on the cache entry, so that should be
+ * quite safe.
+ */
+static ssize_t uwb_dev_IEs_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+       return uwb_bce_print_IEs(uwb_dev, uwb_dev->bce, buf, PAGE_SIZE);
+}
+static DEVICE_ATTR(IEs, S_IRUGO | S_IWUSR, uwb_dev_IEs_show, NULL);
+
+static ssize_t uwb_dev_LQE_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       struct uwb_beca_e *bce = uwb_dev->bce;
+       size_t result;
+
+       mutex_lock(&bce->mutex);
+       result = stats_show(&uwb_dev->bce->lqe_stats, buf);
+       mutex_unlock(&bce->mutex);
+       return result;
+}
+
+static ssize_t uwb_dev_LQE_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_beca_e *bce = uwb_dev->bce;
+       ssize_t result;
+
+       mutex_lock(&bce->mutex);
+       result = stats_store(&uwb_dev->bce->lqe_stats, buf, size);
+       mutex_unlock(&bce->mutex);
+       return result;
+}
+static DEVICE_ATTR(LQE, S_IRUGO | S_IWUSR, uwb_dev_LQE_show, uwb_dev_LQE_store);
+
+static ssize_t uwb_dev_RSSI_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       struct uwb_beca_e *bce = uwb_dev->bce;
+       size_t result;
+
+       mutex_lock(&bce->mutex);
+       result = stats_show(&uwb_dev->bce->rssi_stats, buf);
+       mutex_unlock(&bce->mutex);
+       return result;
+}
+
+static ssize_t uwb_dev_RSSI_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_beca_e *bce = uwb_dev->bce;
+       ssize_t result;
+
+       mutex_lock(&bce->mutex);
+       result = stats_store(&uwb_dev->bce->rssi_stats, buf, size);
+       mutex_unlock(&bce->mutex);
+       return result;
+}
+static DEVICE_ATTR(RSSI, S_IRUGO | S_IWUSR, uwb_dev_RSSI_show, uwb_dev_RSSI_store);
+
+
+static struct attribute *uwb_dev_attrs[] = {
+       &dev_attr_EUI_48.attr,
+       &dev_attr_DevAddr.attr,
+       &dev_attr_BPST.attr,
+       &dev_attr_IEs.attr,
+       &dev_attr_LQE.attr,
+       &dev_attr_RSSI.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(uwb_dev);
+
+/* UWB bus type. */
+struct bus_type uwb_bus_type = {
+       .name =         "uwb",
+       .dev_groups =   uwb_dev_groups,
+};
+
+/**
+ * Device SYSFS registration
+ */
+static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev)
+{
+       struct device *dev;
+
+       dev = &uwb_dev->dev;
+       dev->parent = parent_dev;
+       dev_set_drvdata(dev, uwb_dev);
+
+       return device_add(dev);
+}
+
+
+static void __uwb_dev_sys_rm(struct uwb_dev *uwb_dev)
+{
+       dev_set_drvdata(&uwb_dev->dev, NULL);
+       device_del(&uwb_dev->dev);
+}
+
+
+/**
+ * Register and initialize a new UWB device
+ *
+ * Did you call uwb_dev_init() on it?
+ *
+ * @parent_rc: is the parent radio controller who has the link to the
+ *             device. When registering the UWB device that is a UWB
+ *             Radio Controller, we point back to it.
+ *
+ * If registering the device that is part of a radio, caller has set
+ * rc->uwb_dev->dev. Otherwise it is to be left NULL--a new one will
+ * be allocated.
+ */
+int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
+               struct uwb_rc *parent_rc)
+{
+       int result;
+       struct device *dev;
+
+       BUG_ON(uwb_dev == NULL);
+       BUG_ON(parent_dev == NULL);
+       BUG_ON(parent_rc == NULL);
+
+       mutex_lock(&uwb_dev->mutex);
+       dev = &uwb_dev->dev;
+       uwb_dev->rc = parent_rc;
+       result = __uwb_dev_sys_add(uwb_dev, parent_dev);
+       if (result < 0)
+               printk(KERN_ERR "UWB: unable to register dev %s with sysfs: %d\n",
+                      dev_name(dev), result);
+       mutex_unlock(&uwb_dev->mutex);
+       return result;
+}
+
+
+void uwb_dev_rm(struct uwb_dev *uwb_dev)
+{
+       mutex_lock(&uwb_dev->mutex);
+       __uwb_dev_sys_rm(uwb_dev);
+       mutex_unlock(&uwb_dev->mutex);
+}
+
+
+static
+int __uwb_dev_try_get(struct device *dev, void *__target_uwb_dev)
+{
+       struct uwb_dev *target_uwb_dev = __target_uwb_dev;
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+       if (uwb_dev == target_uwb_dev) {
+               uwb_dev_get(uwb_dev);
+               return 1;
+       } else
+               return 0;
+}
+
+
+/**
+ * Given a UWB device descriptor, validate and refcount it
+ *
+ * @returns NULL if the device does not exist or is quiescing; the ptr to
+ *               it otherwise.
+ */
+struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev)
+{
+       if (uwb_dev_for_each(rc, __uwb_dev_try_get, uwb_dev))
+               return uwb_dev;
+       else
+               return NULL;
+}
+EXPORT_SYMBOL_GPL(uwb_dev_try_get);
+
+
+/**
+ * Remove a device from the system [grunt for other functions]
+ */
+int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc)
+{
+       struct device *dev = &uwb_dev->dev;
+       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+       uwb_mac_addr_print(macbuf, sizeof(macbuf), &uwb_dev->mac_addr);
+       uwb_dev_addr_print(devbuf, sizeof(devbuf), &uwb_dev->dev_addr);
+       dev_info(dev, "uwb device (mac %s dev %s) disconnected from %s %s\n",
+                macbuf, devbuf,
+                uwb_dev->dev.bus->name,
+                rc ? dev_name(&(rc->uwb_dev.dev)) : "");
+       uwb_dev_rm(uwb_dev);
+       list_del(&uwb_dev->bce->node);
+       uwb_bce_put(uwb_dev->bce);
+       uwb_dev_put(uwb_dev);   /* for the creation in _onair() */
+
+       return 0;
+}
+
+
+/**
+ * A device went off the air, clean up after it!
+ *
+ * This is called by the UWB Daemon (through the beacon purge function
+ * uwb_bcn_cache_purge) when it is detected that a device has been in
+ * radio silence for a while.
+ *
+ * If this device is actually a local radio controller we don't need
+ * to go through the offair process, as it is not registered as that.
+ *
+ * NOTE: uwb_bcn_cache.mutex is held!
+ */
+void uwbd_dev_offair(struct uwb_beca_e *bce)
+{
+       struct uwb_dev *uwb_dev;
+
+       uwb_dev = bce->uwb_dev;
+       if (uwb_dev) {
+               uwb_notify(uwb_dev->rc, uwb_dev, UWB_NOTIF_OFFAIR);
+               __uwb_dev_offair(uwb_dev, uwb_dev->rc);
+       }
+}
+
+
+/**
+ * A device went on the air, start it up!
+ *
+ * This is called by the UWB Daemon when it is detected that a device
+ * has popped up in the radio range of the radio controller.
+ *
+ * It will just create the freaking device, register the beacon and
+ * stuff and yatla, done.
+ *
+ *
+ * NOTE: uwb_beca.mutex is held, bce->mutex is held
+ */
+void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce)
+{
+       int result;
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_dev *uwb_dev;
+       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+       uwb_mac_addr_print(macbuf, sizeof(macbuf), bce->mac_addr);
+       uwb_dev_addr_print(devbuf, sizeof(devbuf), &bce->dev_addr);
+       uwb_dev = kzalloc(sizeof(struct uwb_dev), GFP_KERNEL);
+       if (uwb_dev == NULL) {
+               dev_err(dev, "new device %s: Cannot allocate memory\n",
+                       macbuf);
+               return;
+       }
+       uwb_dev_init(uwb_dev);          /* This sets refcnt to one, we own it */
+       uwb_dev->dev.bus = &uwb_bus_type;
+       uwb_dev->mac_addr = *bce->mac_addr;
+       uwb_dev->dev_addr = bce->dev_addr;
+       dev_set_name(&uwb_dev->dev, "%s", macbuf);
+
+       /* plug the beacon cache */
+       bce->uwb_dev = uwb_dev;
+       uwb_dev->bce = bce;
+       uwb_bce_get(bce);               /* released in uwb_dev_sys_release() */
+
+       result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc);
+       if (result < 0) {
+               dev_err(dev, "new device %s: cannot instantiate device\n",
+                       macbuf);
+               goto error_dev_add;
+       }
+
+       dev_info(dev, "uwb device (mac %s dev %s) connected to %s %s\n",
+                macbuf, devbuf, uwb_dev->dev.bus->name,
+                dev_name(&(rc->uwb_dev.dev)));
+       uwb_notify(rc, uwb_dev, UWB_NOTIF_ONAIR);
+       return;
+
+error_dev_add:
+       bce->uwb_dev = NULL;
+       uwb_bce_put(bce);
+       kfree(uwb_dev);
+       return;
+}
+
+/**
+ * Iterate over the list of UWB devices, calling a @function on each
+ *
+ * See docs for bus_for_each()....
+ *
+ * @rc:       radio controller for the devices.
+ * @function: function to call.
+ * @priv:     data to pass to @function.
+ * @returns:  0 if no invocation of function() returned a value
+ *            different to zero. That value otherwise.
+ */
+int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f function, void *priv)
+{
+       return device_for_each_child(&rc->uwb_dev.dev, priv, function);
+}
+EXPORT_SYMBOL_GPL(uwb_dev_for_each);
diff --git a/drivers/staging/uwb/lc-rc.c b/drivers/staging/uwb/lc-rc.c
new file mode 100644 (file)
index 0000000..ee31b22
--- /dev/null
@@ -0,0 +1,569 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Life cycle of radio controllers
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ *
+ * A UWB radio controller is also a UWB device, so it embeds one...
+ *
+ * List of RCs comes from the 'struct class uwb_rc_class'.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/random.h>
+#include <linux/kdev_t.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "uwb-internal.h"
+
+static int uwb_rc_index_match(struct device *dev, const void *data)
+{
+       const int *index = data;
+       struct uwb_rc *rc = dev_get_drvdata(dev);
+
+       if (rc->index == *index)
+               return 1;
+       return 0;
+}
+
+static struct uwb_rc *uwb_rc_find_by_index(int index)
+{
+       struct device *dev;
+       struct uwb_rc *rc = NULL;
+
+       dev = class_find_device(&uwb_rc_class, NULL, &index, uwb_rc_index_match);
+       if (dev) {
+               rc = dev_get_drvdata(dev);
+               put_device(dev);
+       }
+
+       return rc;
+}
+
+static int uwb_rc_new_index(void)
+{
+       int index = 0;
+
+       for (;;) {
+               if (!uwb_rc_find_by_index(index))
+                       return index;
+               if (++index < 0)
+                       index = 0;
+       }
+}
+
+/**
+ * Release the backing device of a uwb_rc that has been dynamically allocated.
+ */
+static void uwb_rc_sys_release(struct device *dev)
+{
+       struct uwb_dev *uwb_dev = container_of(dev, struct uwb_dev, dev);
+       struct uwb_rc *rc = container_of(uwb_dev, struct uwb_rc, uwb_dev);
+
+       uwb_rc_ie_release(rc);
+       kfree(rc);
+}
+
+
+void uwb_rc_init(struct uwb_rc *rc)
+{
+       struct uwb_dev *uwb_dev = &rc->uwb_dev;
+
+       uwb_dev_init(uwb_dev);
+       rc->uwb_dev.dev.class = &uwb_rc_class;
+       rc->uwb_dev.dev.release = uwb_rc_sys_release;
+       uwb_rc_neh_create(rc);
+       rc->beaconing = -1;
+       rc->scan_type = UWB_SCAN_DISABLED;
+       INIT_LIST_HEAD(&rc->notifs_chain.list);
+       mutex_init(&rc->notifs_chain.mutex);
+       INIT_LIST_HEAD(&rc->uwb_beca.list);
+       mutex_init(&rc->uwb_beca.mutex);
+       uwb_drp_avail_init(rc);
+       uwb_rc_ie_init(rc);
+       uwb_rsv_init(rc);
+       uwb_rc_pal_init(rc);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_init);
+
+
+struct uwb_rc *uwb_rc_alloc(void)
+{
+       struct uwb_rc *rc;
+       rc = kzalloc(sizeof(*rc), GFP_KERNEL);
+       if (rc == NULL)
+               return NULL;
+       uwb_rc_init(rc);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_alloc);
+
+/*
+ * Show the ASIE that is broadcast in the UWB beacon by this uwb_rc device.
+ */
+static ssize_t ASIE_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_ie_hdr *ie;
+       void *ptr;
+       size_t len;
+       int result = 0;
+
+       /* init empty buffer. */
+       result = scnprintf(buf, PAGE_SIZE, "\n");
+       mutex_lock(&rc->ies_mutex);
+       /* walk IEData looking for an ASIE. */
+       ptr = rc->ies->IEData;
+       len = le16_to_cpu(rc->ies->wIELength);
+       for (;;) {
+               ie = uwb_ie_next(&ptr, &len);
+               if (!ie)
+                       break;
+               if (ie->element_id == UWB_APP_SPEC_IE) {
+                       result = uwb_ie_dump_hex(ie,
+                                       ie->length + sizeof(struct uwb_ie_hdr),
+                                       buf, PAGE_SIZE);
+                       break;
+               }
+       }
+       mutex_unlock(&rc->ies_mutex);
+
+       return result;
+}
+
+/*
+ * Update the ASIE that is broadcast in the UWB beacon by this uwb_rc device.
+ */
+static ssize_t ASIE_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;
+       char ie_buf[255];
+       int result, ie_len = 0;
+       const char *cur_ptr = buf;
+       struct uwb_ie_hdr *ie;
+
+       /* empty string means clear the ASIE. */
+       if (strlen(buf) <= 1) {
+               uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE);
+               return size;
+       }
+
+       /* if non-empty string, convert string of hex chars to binary. */
+       while (ie_len < sizeof(ie_buf)) {
+               int char_count;
+
+               if (sscanf(cur_ptr, " %02hhX %n",
+                               &(ie_buf[ie_len]), &char_count) > 0) {
+                       ++ie_len;
+                       /* skip chars read from cur_ptr. */
+                       cur_ptr += char_count;
+               } else {
+                       break;
+               }
+       }
+
+       /* validate IE length and type. */
+       if (ie_len < sizeof(struct uwb_ie_hdr)) {
+               dev_err(dev, "%s: Invalid ASIE size %d.\n", __func__, ie_len);
+               return -EINVAL;
+       }
+
+       ie = (struct uwb_ie_hdr *)ie_buf;
+       if (ie->element_id != UWB_APP_SPEC_IE) {
+               dev_err(dev, "%s: Invalid IE element type size = 0x%02X.\n",
+                               __func__, ie->element_id);
+               return -EINVAL;
+       }
+
+       /* bounds check length field from user. */
+       if (ie->length > (ie_len - sizeof(struct uwb_ie_hdr)))
+               ie->length = ie_len - sizeof(struct uwb_ie_hdr);
+
+       /*
+        * Valid ASIE received. Remove current ASIE then add the new one using
+        * uwb_rc_ie_add.
+        */
+       uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE);
+
+       result = uwb_rc_ie_add(rc, ie, ie->length + sizeof(struct uwb_ie_hdr));
+
+       return result >= 0 ? size : result;
+}
+static DEVICE_ATTR_RW(ASIE);
+
+static struct attribute *rc_attrs[] = {
+               &dev_attr_mac_address.attr,
+               &dev_attr_scan.attr,
+               &dev_attr_beacon.attr,
+               &dev_attr_ASIE.attr,
+               NULL,
+};
+
+static const struct attribute_group rc_attr_group = {
+       .attrs = rc_attrs,
+};
+
+/*
+ * Registration of sysfs specific stuff
+ */
+static int uwb_rc_sys_add(struct uwb_rc *rc)
+{
+       return sysfs_create_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
+}
+
+
+static void __uwb_rc_sys_rm(struct uwb_rc *rc)
+{
+       sysfs_remove_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
+}
+
+/**
+ * uwb_rc_mac_addr_setup - get an RC's EUI-48 address or set it
+ * @rc:  the radio controller.
+ *
+ * If the EUI-48 address is 00:00:00:00:00:00 or FF:FF:FF:FF:FF:FF
+ * then a random locally administered EUI-48 is generated and set on
+ * the device.  The probability of address collisions is sufficiently
+ * unlikely (1/2^40 = 9.1e-13) that they're not checked for.
+ */
+static
+int uwb_rc_mac_addr_setup(struct uwb_rc *rc)
+{
+       int result;
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_dev *uwb_dev = &rc->uwb_dev;
+       char devname[UWB_ADDR_STRSIZE];
+       struct uwb_mac_addr addr;
+
+       result = uwb_rc_mac_addr_get(rc, &addr);
+       if (result < 0) {
+               dev_err(dev, "cannot retrieve UWB EUI-48 address: %d\n", result);
+               return result;
+       }
+
+       if (uwb_mac_addr_unset(&addr) || uwb_mac_addr_bcast(&addr)) {
+               addr.data[0] = 0x02; /* locally administered and unicast */
+               get_random_bytes(&addr.data[1], sizeof(addr.data)-1);
+
+               result = uwb_rc_mac_addr_set(rc, &addr);
+               if (result < 0) {
+                       uwb_mac_addr_print(devname, sizeof(devname), &addr);
+                       dev_err(dev, "cannot set EUI-48 address %s: %d\n",
+                               devname, result);
+                       return result;
+               }
+       }
+       uwb_dev->mac_addr = addr;
+       return 0;
+}
+
+
+
+static int uwb_rc_setup(struct uwb_rc *rc)
+{
+       int result;
+       struct device *dev = &rc->uwb_dev.dev;
+
+       result = uwb_radio_setup(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot setup UWB radio: %d\n", result);
+               goto error;
+       }
+       result = uwb_rc_mac_addr_setup(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot setup UWB MAC address: %d\n", result);
+               goto error;
+       }
+       result = uwb_rc_dev_addr_assign(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot assign UWB DevAddr: %d\n", result);
+               goto error;
+       }
+       result = uwb_rc_ie_setup(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot setup IE subsystem: %d\n", result);
+               goto error_ie_setup;
+       }
+       result = uwb_rsv_setup(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot setup reservation subsystem: %d\n", result);
+               goto error_rsv_setup;
+       }
+       uwb_dbg_add_rc(rc);
+       return 0;
+
+error_rsv_setup:
+       uwb_rc_ie_release(rc);
+error_ie_setup:
+error:
+       return result;
+}
+
+
+/**
+ * Register a new UWB radio controller
+ *
+ * Did you call uwb_rc_init() on your rc?
+ *
+ * We assume that this is being called with a > 0 refcount on
+ * it [through ops->{get|put}_device(). We'll take our own, though.
+ *
+ * @parent_dev is our real device, the one that provides the actual UWB device
+ */
+int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv)
+{
+       int result;
+       struct device *dev;
+       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
+
+       rc->index = uwb_rc_new_index();
+
+       dev = &rc->uwb_dev.dev;
+       dev_set_name(dev, "uwb%d", rc->index);
+
+       rc->priv = priv;
+
+       init_waitqueue_head(&rc->uwbd.wq);
+       INIT_LIST_HEAD(&rc->uwbd.event_list);
+       spin_lock_init(&rc->uwbd.event_list_lock);
+
+       uwbd_start(rc);
+
+       result = rc->start(rc);
+       if (result < 0)
+               goto error_rc_start;
+
+       result = uwb_rc_setup(rc);
+       if (result < 0) {
+               dev_err(dev, "cannot setup UWB radio controller: %d\n", result);
+               goto error_rc_setup;
+       }
+
+       result = uwb_dev_add(&rc->uwb_dev, parent_dev, rc);
+       if (result < 0 && result != -EADDRNOTAVAIL)
+               goto error_dev_add;
+
+       result = uwb_rc_sys_add(rc);
+       if (result < 0) {
+               dev_err(parent_dev, "cannot register UWB radio controller "
+                       "dev attributes: %d\n", result);
+               goto error_sys_add;
+       }
+
+       uwb_mac_addr_print(macbuf, sizeof(macbuf), &rc->uwb_dev.mac_addr);
+       uwb_dev_addr_print(devbuf, sizeof(devbuf), &rc->uwb_dev.dev_addr);
+       dev_info(dev,
+                "new uwb radio controller (mac %s dev %s) on %s %s\n",
+                macbuf, devbuf, parent_dev->bus->name, dev_name(parent_dev));
+       rc->ready = 1;
+       return 0;
+
+error_sys_add:
+       uwb_dev_rm(&rc->uwb_dev);
+error_dev_add:
+error_rc_setup:
+       rc->stop(rc);
+error_rc_start:
+       uwbd_stop(rc);
+       return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_add);
+
+
+static int uwb_dev_offair_helper(struct device *dev, void *priv)
+{
+       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
+
+       return __uwb_dev_offair(uwb_dev, uwb_dev->rc);
+}
+
+/*
+ * Remove a Radio Controller; stop beaconing/scanning, disconnect all children
+ */
+void uwb_rc_rm(struct uwb_rc *rc)
+{
+       rc->ready = 0;
+
+       uwb_dbg_del_rc(rc);
+       uwb_rsv_remove_all(rc);
+       uwb_radio_shutdown(rc);
+
+       rc->stop(rc);
+
+       uwbd_stop(rc);
+       uwb_rc_neh_destroy(rc);
+
+       uwb_dev_lock(&rc->uwb_dev);
+       rc->priv = NULL;
+       rc->cmd = NULL;
+       uwb_dev_unlock(&rc->uwb_dev);
+       mutex_lock(&rc->uwb_beca.mutex);
+       uwb_dev_for_each(rc, uwb_dev_offair_helper, NULL);
+       __uwb_rc_sys_rm(rc);
+       mutex_unlock(&rc->uwb_beca.mutex);
+       uwb_rsv_cleanup(rc);
+       uwb_beca_release(rc);
+       uwb_dev_rm(&rc->uwb_dev);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_rm);
+
+static int find_rc_try_get(struct device *dev, const void *data)
+{
+       const struct uwb_rc *target_rc = data;
+       struct uwb_rc *rc = dev_get_drvdata(dev);
+
+       if (rc == NULL) {
+               WARN_ON(1);
+               return 0;
+       }
+       if (rc == target_rc) {
+               if (rc->ready == 0)
+                       return 0;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+/**
+ * Given a radio controller descriptor, validate and refcount it
+ *
+ * @returns NULL if the rc does not exist or is quiescing; the ptr to
+ *               it otherwise.
+ */
+struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *target_rc)
+{
+       struct device *dev;
+       struct uwb_rc *rc = NULL;
+
+       dev = class_find_device(&uwb_rc_class, NULL, target_rc,
+                               find_rc_try_get);
+       if (dev) {
+               rc = dev_get_drvdata(dev);
+               __uwb_rc_get(rc);
+               put_device(dev);
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(__uwb_rc_try_get);
+
+/*
+ * RC get for external refcount acquirers...
+ *
+ * Increments the refcount of the device and it's backend modules
+ */
+static inline struct uwb_rc *uwb_rc_get(struct uwb_rc *rc)
+{
+       if (rc->ready == 0)
+               return NULL;
+       uwb_dev_get(&rc->uwb_dev);
+       return rc;
+}
+
+static int find_rc_grandpa(struct device *dev, const void *data)
+{
+       const struct device *grandpa_dev = data;
+       struct uwb_rc *rc = dev_get_drvdata(dev);
+
+       if (rc->uwb_dev.dev.parent->parent == grandpa_dev) {
+               rc = uwb_rc_get(rc);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * Locate and refcount a radio controller given a common grand-parent
+ *
+ * @grandpa_dev  Pointer to the 'grandparent' device structure.
+ * @returns NULL If the rc does not exist or is quiescing; the ptr to
+ *               it otherwise, properly referenced.
+ *
+ * The Radio Control interface (or the UWB Radio Controller) is always
+ * an interface of a device. The parent is the interface, the
+ * grandparent is the device that encapsulates the interface.
+ *
+ * There is no need to lock around as the "grandpa" would be
+ * refcounted by the target, and to remove the referemes, the
+ * uwb_rc_class->sem would have to be taken--we hold it, ergo we
+ * should be safe.
+ */
+struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev)
+{
+       struct device *dev;
+       struct uwb_rc *rc = NULL;
+
+       dev = class_find_device(&uwb_rc_class, NULL, grandpa_dev,
+                               find_rc_grandpa);
+       if (dev) {
+               rc = dev_get_drvdata(dev);
+               put_device(dev);
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa);
+
+/**
+ * Find a radio controller by device address
+ *
+ * @returns the pointer to the radio controller, properly referenced
+ */
+static int find_rc_dev(struct device *dev, const void *data)
+{
+       const struct uwb_dev_addr *addr = data;
+       struct uwb_rc *rc = dev_get_drvdata(dev);
+
+       if (rc == NULL) {
+               WARN_ON(1);
+               return 0;
+       }
+       if (!uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, addr)) {
+               rc = uwb_rc_get(rc);
+               return 1;
+       }
+       return 0;
+}
+
+struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr)
+{
+       struct device *dev;
+       struct uwb_rc *rc = NULL;
+
+       dev = class_find_device(&uwb_rc_class, NULL, addr, find_rc_dev);
+       if (dev) {
+               rc = dev_get_drvdata(dev);
+               put_device(dev);
+       }
+
+       return rc;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_get_by_dev);
+
+/**
+ * Drop a reference on a radio controller
+ *
+ * This is the version that should be done by entities external to the
+ * UWB Radio Control stack (ie: clients of the API).
+ */
+void uwb_rc_put(struct uwb_rc *rc)
+{
+       __uwb_rc_put(rc);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_put);
diff --git a/drivers/staging/uwb/neh.c b/drivers/staging/uwb/neh.c
new file mode 100644 (file)
index 0000000..1695584
--- /dev/null
@@ -0,0 +1,606 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * WUSB Wire Adapter: Radio Control Interface (WUSB[8])
+ * Notification and Event Handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * The RC interface of the Host Wire Adapter (USB dongle) or WHCI PCI
+ * card delivers a stream of notifications and events to the
+ * notification end event endpoint or area. This code takes care of
+ * getting a buffer with that data, breaking it up in separate
+ * notifications and events and then deliver those.
+ *
+ * Events are answers to commands and they carry a context ID that
+ * associates them to the command. Notifications are that,
+ * notifications, they come out of the blue and have a context ID of
+ * zero. Think of the context ID kind of like a handler. The
+ * uwb_rc_neh_* code deals with managing context IDs.
+ *
+ * This is why you require a handle to operate on a UWB host. When you
+ * open a handle a context ID is assigned to you.
+ *
+ * So, as it is done is:
+ *
+ * 1. Add an event handler [uwb_rc_neh_add()] (assigns a ctx id)
+ * 2. Issue command [rc->cmd(rc, ...)]
+ * 3. Arm the timeout timer [uwb_rc_neh_arm()]
+ * 4, Release the reference to the neh [uwb_rc_neh_put()]
+ * 5. Wait for the callback
+ * 6. Command result (RCEB) is passed to the callback
+ *
+ * If (2) fails, you should remove the handle [uwb_rc_neh_rm()]
+ * instead of arming the timer.
+ *
+ * Handles are for using in *serialized* code, single thread.
+ *
+ * When the notification/event comes, the IRQ handler/endpoint
+ * callback passes the data read to uwb_rc_neh_grok() which will break
+ * it up in a discrete series of events, look up who is listening for
+ * them and execute the pertinent callbacks.
+ *
+ * If the reader detects an error while reading the data stream, call
+ * uwb_rc_neh_error().
+ *
+ * CONSTRAINTS/ASSUMPTIONS:
+ *
+ * - Most notifications/events are small (less thank .5k), copying
+ *   around is ok.
+ *
+ * - Notifications/events are ALWAYS smaller than PAGE_SIZE
+ *
+ * - Notifications/events always come in a single piece (ie: a buffer
+ *   will always contain entire notifications/events).
+ *
+ * - we cannot know in advance how long each event is (because they
+ *   lack a length field in their header--smart move by the standards
+ *   body, btw). So we need a facility to get the event size given the
+ *   header. This is what the EST code does (notif/Event Size
+ *   Tables), check nest.c--as well, you can associate the size to
+ *   the handle [w/ neh->extra_size()].
+ *
+ * - Most notifications/events are fixed size; only a few are variable
+ *   size (NEST takes care of that).
+ *
+ * - Listeners of events expect them, so they usually provide a
+ *   buffer, as they know the size. Listeners to notifications don't,
+ *   so we allocate their buffers dynamically.
+ */
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/export.h>
+
+#include "uwb-internal.h"
+
+/*
+ * UWB Radio Controller Notification/Event Handle
+ *
+ * Represents an entity waiting for an event coming from the UWB Radio
+ * Controller with a given context id (context) and type (evt_type and
+ * evt). On reception of the notification/event, the callback (cb) is
+ * called with the event.
+ *
+ * If the timer expires before the event is received, the callback is
+ * called with -ETIMEDOUT as the event size.
+ */
+struct uwb_rc_neh {
+       struct kref kref;
+
+       struct uwb_rc *rc;
+       u8 evt_type;
+       __le16 evt;
+       u8 context;
+       u8 completed;
+       uwb_rc_cmd_cb_f cb;
+       void *arg;
+
+       struct timer_list timer;
+       struct list_head list_node;
+};
+
+static void uwb_rc_neh_timer(struct timer_list *t);
+
+static void uwb_rc_neh_release(struct kref *kref)
+{
+       struct uwb_rc_neh *neh = container_of(kref, struct uwb_rc_neh, kref);
+
+       kfree(neh);
+}
+
+static void uwb_rc_neh_get(struct uwb_rc_neh *neh)
+{
+       kref_get(&neh->kref);
+}
+
+/**
+ * uwb_rc_neh_put - release reference to a neh
+ * @neh: the neh
+ */
+void uwb_rc_neh_put(struct uwb_rc_neh *neh)
+{
+       kref_put(&neh->kref, uwb_rc_neh_release);
+}
+
+
+/**
+ * Assigns @neh a context id from @rc's pool
+ *
+ * @rc:            UWB Radio Controller descriptor; @rc->neh_lock taken
+ * @neh:    Notification/Event Handle
+ * @returns 0 if context id was assigned ok; < 0 errno on error (if
+ *         all the context IDs are taken).
+ *
+ * (assumes @wa is locked).
+ *
+ * NOTE: WUSB spec reserves context ids 0x00 for notifications and
+ *      0xff is invalid, so they must not be used. Initialization
+ *      fills up those two in the bitmap so they are not allocated.
+ *
+ * We spread the allocation around to reduce the possibility of two
+ * consecutive opened @neh's getting the same context ID assigned (to
+ * avoid surprises with late events that timed out long time ago). So
+ * first we search from where @rc->ctx_roll is, if not found, we
+ * search from zero.
+ */
+static
+int __uwb_rc_ctx_get(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+       int result;
+       result = find_next_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX,
+                                   rc->ctx_roll++);
+       if (result < UWB_RC_CTX_MAX)
+               goto found;
+       result = find_first_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX);
+       if (result < UWB_RC_CTX_MAX)
+               goto found;
+       return -ENFILE;
+found:
+       set_bit(result, rc->ctx_bm);
+       neh->context = result;
+       return 0;
+}
+
+
+/** Releases @neh's context ID back to @rc (@rc->neh_lock is locked). */
+static
+void __uwb_rc_ctx_put(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       if (neh->context == 0)
+               return;
+       if (test_bit(neh->context, rc->ctx_bm) == 0) {
+               dev_err(dev, "context %u not set in bitmap\n",
+                       neh->context);
+               WARN_ON(1);
+       }
+       clear_bit(neh->context, rc->ctx_bm);
+       neh->context = 0;
+}
+
+/**
+ * uwb_rc_neh_add - add a neh for a radio controller command
+ * @rc:             the radio controller
+ * @cmd:            the radio controller command
+ * @expected_type:  the type of the expected response event
+ * @expected_event: the expected event ID
+ * @cb:             callback for when the event is received
+ * @arg:            argument for the callback
+ *
+ * Creates a neh and adds it to the list of those waiting for an
+ * event.  A context ID will be assigned to the command.
+ */
+struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
+                                 u8 expected_type, u16 expected_event,
+                                 uwb_rc_cmd_cb_f cb, void *arg)
+{
+       int result;
+       unsigned long flags;
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_rc_neh *neh;
+
+       neh = kzalloc(sizeof(*neh), GFP_KERNEL);
+       if (neh == NULL) {
+               result = -ENOMEM;
+               goto error_kzalloc;
+       }
+
+       kref_init(&neh->kref);
+       INIT_LIST_HEAD(&neh->list_node);
+       timer_setup(&neh->timer, uwb_rc_neh_timer, 0);
+
+       neh->rc = rc;
+       neh->evt_type = expected_type;
+       neh->evt = cpu_to_le16(expected_event);
+       neh->cb = cb;
+       neh->arg = arg;
+
+       spin_lock_irqsave(&rc->neh_lock, flags);
+       result = __uwb_rc_ctx_get(rc, neh);
+       if (result >= 0) {
+               cmd->bCommandContext = neh->context;
+               list_add_tail(&neh->list_node, &rc->neh_list);
+               uwb_rc_neh_get(neh);
+       }
+       spin_unlock_irqrestore(&rc->neh_lock, flags);
+       if (result < 0)
+               goto error_ctx_get;
+
+       return neh;
+
+error_ctx_get:
+       kfree(neh);
+error_kzalloc:
+       dev_err(dev, "cannot open handle to radio controller: %d\n", result);
+       return ERR_PTR(result);
+}
+
+static void __uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+       __uwb_rc_ctx_put(rc, neh);
+       list_del(&neh->list_node);
+}
+
+/**
+ * uwb_rc_neh_rm - remove a neh.
+ * @rc:  the radio controller
+ * @neh: the neh to remove
+ *
+ * Remove an active neh immediately instead of waiting for the event
+ * (or a time out).
+ */
+void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&rc->neh_lock, flags);
+       __uwb_rc_neh_rm(rc, neh);
+       spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+       del_timer_sync(&neh->timer);
+       uwb_rc_neh_put(neh);
+}
+
+/**
+ * uwb_rc_neh_arm - arm an event handler timeout timer
+ *
+ * @rc:     UWB Radio Controller
+ * @neh:    Notification/event handler for @rc
+ *
+ * The timer is only armed if the neh is active.
+ */
+void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&rc->neh_lock, flags);
+       if (neh->context)
+               mod_timer(&neh->timer,
+                         jiffies + msecs_to_jiffies(UWB_RC_CMD_TIMEOUT_MS));
+       spin_unlock_irqrestore(&rc->neh_lock, flags);
+}
+
+static void uwb_rc_neh_cb(struct uwb_rc_neh *neh, struct uwb_rceb *rceb, size_t size)
+{
+       (*neh->cb)(neh->rc, neh->arg, rceb, size);
+       uwb_rc_neh_put(neh);
+}
+
+static bool uwb_rc_neh_match(struct uwb_rc_neh *neh, const struct uwb_rceb *rceb)
+{
+       return neh->evt_type == rceb->bEventType
+               && neh->evt == rceb->wEvent
+               && neh->context == rceb->bEventContext;
+}
+
+/**
+ * Find the handle waiting for a RC Radio Control Event
+ *
+ * @rc:         UWB Radio Controller
+ * @rceb:       Pointer to the RCEB buffer
+ * @event_size: Pointer to the size of the RCEB buffer. Might be
+ *              adjusted to take into account the @neh->extra_size
+ *              settings.
+ *
+ * If the listener has no buffer (NULL buffer), one is allocated for
+ * the right size (the amount of data received). @neh->ptr will point
+ * to the event payload, which always starts with a 'struct
+ * uwb_rceb'. kfree() it when done.
+ */
+static
+struct uwb_rc_neh *uwb_rc_neh_lookup(struct uwb_rc *rc,
+                                    const struct uwb_rceb *rceb)
+{
+       struct uwb_rc_neh *neh = NULL, *h;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rc->neh_lock, flags);
+
+       list_for_each_entry(h, &rc->neh_list, list_node) {
+               if (uwb_rc_neh_match(h, rceb)) {
+                       neh = h;
+                       break;
+               }
+       }
+
+       if (neh)
+               __uwb_rc_neh_rm(rc, neh);
+
+       spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+       return neh;
+}
+
+
+/*
+ * Process notifications coming from the radio control interface
+ *
+ * @rc:    UWB Radio Control Interface descriptor
+ * @neh:   Notification/Event Handler @neh->ptr points to
+ *         @uwb_evt->buffer.
+ *
+ * This function is called by the event/notif handling subsystem when
+ * notifications arrive (hwarc_probe() arms a notification/event handle
+ * that calls back this function for every received notification; this
+ * function then will rearm itself).
+ *
+ * Notification data buffers are dynamically allocated by the NEH
+ * handling code in neh.c [uwb_rc_neh_lookup()]. What is actually
+ * allocated is space to contain the notification data.
+ *
+ * Buffers are prefixed with a Radio Control Event Block (RCEB) as
+ * defined by the WUSB Wired-Adapter Radio Control interface. We
+ * just use it for the notification code.
+ *
+ * On each case statement we just transcode endianess of the different
+ * fields. We declare a pointer to a RCI definition of an event, and
+ * then to a UWB definition of the same event (which are the same,
+ * remember). Event if we use different pointers
+ */
+static
+void uwb_rc_notif(struct uwb_rc *rc, struct uwb_rceb *rceb, ssize_t size)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_event *uwb_evt;
+
+       if (size == -ESHUTDOWN)
+               return;
+       if (size < 0) {
+               dev_err(dev, "ignoring event with error code %zu\n",
+                       size);
+               return;
+       }
+
+       uwb_evt = kzalloc(sizeof(*uwb_evt), GFP_ATOMIC);
+       if (unlikely(uwb_evt == NULL)) {
+               dev_err(dev, "no memory to queue event 0x%02x/%04x/%02x\n",
+                       rceb->bEventType, le16_to_cpu(rceb->wEvent),
+                       rceb->bEventContext);
+               return;
+       }
+       uwb_evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */
+       uwb_evt->ts_jiffies = jiffies;
+       uwb_evt->type = UWB_EVT_TYPE_NOTIF;
+       uwb_evt->notif.size = size;
+       uwb_evt->notif.rceb = rceb;
+
+       uwbd_event_queue(uwb_evt);
+}
+
+static void uwb_rc_neh_grok_event(struct uwb_rc *rc, struct uwb_rceb *rceb, size_t size)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_rc_neh *neh;
+       struct uwb_rceb *notif;
+       unsigned long flags;
+
+       if (rceb->bEventContext == 0) {
+               notif = kmalloc(size, GFP_ATOMIC);
+               if (notif) {
+                       memcpy(notif, rceb, size);
+                       uwb_rc_notif(rc, notif, size);
+               } else
+                       dev_err(dev, "event 0x%02x/%04x/%02x (%zu bytes): no memory\n",
+                               rceb->bEventType, le16_to_cpu(rceb->wEvent),
+                               rceb->bEventContext, size);
+       } else {
+               neh = uwb_rc_neh_lookup(rc, rceb);
+               if (neh) {
+                       spin_lock_irqsave(&rc->neh_lock, flags);
+                       /* to guard against a timeout */
+                       neh->completed = 1;
+                       del_timer(&neh->timer);
+                       spin_unlock_irqrestore(&rc->neh_lock, flags);
+                       uwb_rc_neh_cb(neh, rceb, size);
+               } else
+                       dev_warn(dev, "event 0x%02x/%04x/%02x (%zu bytes): nobody cared\n",
+                                rceb->bEventType, le16_to_cpu(rceb->wEvent),
+                                rceb->bEventContext, size);
+       }
+}
+
+/**
+ * Given a buffer with one or more UWB RC events/notifications, break
+ * them up and dispatch them.
+ *
+ * @rc:              UWB Radio Controller
+ * @buf:      Buffer with the stream of notifications/events
+ * @buf_size: Amount of data in the buffer
+ *
+ * Note each notification/event starts always with a 'struct
+ * uwb_rceb', so the minimum size if 4 bytes.
+ *
+ * The device may pass us events formatted differently than expected.
+ * These are first filtered, potentially creating a new event in a new
+ * memory location. If a new event is created by the filter it is also
+ * freed here.
+ *
+ * For each notif/event, tries to guess the size looking at the EST
+ * tables, then looks for a neh that is waiting for that event and if
+ * found, copies the payload to the neh's buffer and calls it back. If
+ * not, the data is ignored.
+ *
+ * Note that if we can't find a size description in the EST tables, we
+ * still might find a size in the 'neh' handle in uwb_rc_neh_lookup().
+ *
+ * Assumptions:
+ *
+ *   @rc->neh_lock is NOT taken
+ *
+ * We keep track of various sizes here:
+ * size:      contains the size of the buffer that is processed for the
+ *            incoming event. this buffer may contain events that are not
+ *            formatted as WHCI.
+ * real_size: the actual space taken by this event in the buffer.
+ *            We need to keep track of the real size of an event to be able to
+ *            advance the buffer correctly.
+ * event_size: the size of the event as expected by the core layer
+ *            [OR] the size of the event after filtering. if the filtering
+ *            created a new event in a new memory location then this is
+ *            effectively the size of a new event buffer
+ */
+void uwb_rc_neh_grok(struct uwb_rc *rc, void *buf, size_t buf_size)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       void *itr;
+       struct uwb_rceb *rceb;
+       size_t size, real_size, event_size;
+       int needtofree;
+
+       itr = buf;
+       size = buf_size;
+       while (size > 0) {
+               if (size < sizeof(*rceb)) {
+                       dev_err(dev, "not enough data in event buffer to "
+                               "process incoming events (%zu left, minimum is "
+                               "%zu)\n", size, sizeof(*rceb));
+                       break;
+               }
+
+               rceb = itr;
+               if (rc->filter_event) {
+                       needtofree = rc->filter_event(rc, &rceb, size,
+                                                     &real_size, &event_size);
+                       if (needtofree < 0 && needtofree != -ENOANO) {
+                               dev_err(dev, "BUG: Unable to filter event "
+                                       "(0x%02x/%04x/%02x) from "
+                                       "device. \n", rceb->bEventType,
+                                       le16_to_cpu(rceb->wEvent),
+                                       rceb->bEventContext);
+                               break;
+                       }
+               } else
+                       needtofree = -ENOANO;
+               /* do real processing if there was no filtering or the
+                * filtering didn't act */
+               if (needtofree == -ENOANO) {
+                       ssize_t ret = uwb_est_find_size(rc, rceb, size);
+                       if (ret < 0)
+                               break;
+                       if (ret > size) {
+                               dev_err(dev, "BUG: hw sent incomplete event "
+                                       "0x%02x/%04x/%02x (%zd bytes), only got "
+                                       "%zu bytes. We don't handle that.\n",
+                                       rceb->bEventType, le16_to_cpu(rceb->wEvent),
+                                       rceb->bEventContext, ret, size);
+                               break;
+                       }
+                       real_size = event_size = ret;
+               }
+               uwb_rc_neh_grok_event(rc, rceb, event_size);
+
+               if (needtofree == 1)
+                       kfree(rceb);
+
+               itr += real_size;
+               size -= real_size;
+       }
+}
+EXPORT_SYMBOL_GPL(uwb_rc_neh_grok);
+
+
+/**
+ * The entity that reads from the device notification/event channel has
+ * detected an error.
+ *
+ * @rc:    UWB Radio Controller
+ * @error: Errno error code
+ *
+ */
+void uwb_rc_neh_error(struct uwb_rc *rc, int error)
+{
+       struct uwb_rc_neh *neh;
+       unsigned long flags;
+
+       for (;;) {
+               spin_lock_irqsave(&rc->neh_lock, flags);
+               if (list_empty(&rc->neh_list)) {
+                       spin_unlock_irqrestore(&rc->neh_lock, flags);
+                       break;
+               }
+               neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node);
+               __uwb_rc_neh_rm(rc, neh);
+               spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+               del_timer_sync(&neh->timer);
+               uwb_rc_neh_cb(neh, NULL, error);
+       }
+}
+EXPORT_SYMBOL_GPL(uwb_rc_neh_error);
+
+
+static void uwb_rc_neh_timer(struct timer_list *t)
+{
+       struct uwb_rc_neh *neh = from_timer(neh, t, timer);
+       struct uwb_rc *rc = neh->rc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rc->neh_lock, flags);
+       if (neh->completed) {
+               spin_unlock_irqrestore(&rc->neh_lock, flags);
+               return;
+       }
+       if (neh->context)
+               __uwb_rc_neh_rm(rc, neh);
+       else
+               neh = NULL;
+       spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+       if (neh)
+               uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT);
+}
+
+/** Initializes the @rc's neh subsystem
+ */
+void uwb_rc_neh_create(struct uwb_rc *rc)
+{
+       spin_lock_init(&rc->neh_lock);
+       INIT_LIST_HEAD(&rc->neh_list);
+       set_bit(0, rc->ctx_bm);         /* 0 is reserved (see [WUSB] table 8-65) */
+       set_bit(0xff, rc->ctx_bm);      /* and 0xff is invalid */
+       rc->ctx_roll = 1;
+}
+
+
+/** Release's the @rc's neh subsystem */
+void uwb_rc_neh_destroy(struct uwb_rc *rc)
+{
+       unsigned long flags;
+       struct uwb_rc_neh *neh;
+
+       for (;;) {
+               spin_lock_irqsave(&rc->neh_lock, flags);
+               if (list_empty(&rc->neh_list)) {
+                       spin_unlock_irqrestore(&rc->neh_lock, flags);
+                       break;
+               }
+               neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node);
+               __uwb_rc_neh_rm(rc, neh);
+               spin_unlock_irqrestore(&rc->neh_lock, flags);
+
+               del_timer_sync(&neh->timer);
+               uwb_rc_neh_put(neh);
+       }
+}
diff --git a/drivers/staging/uwb/pal.c b/drivers/staging/uwb/pal.c
new file mode 100644 (file)
index 0000000..a541e64
--- /dev/null
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UWB PAL support.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/export.h>
+
+#include "uwb.h"
+#include "uwb-internal.h"
+
+/**
+ * uwb_pal_init - initialize a UWB PAL
+ * @pal: the PAL to initialize
+ */
+void uwb_pal_init(struct uwb_pal *pal)
+{
+       INIT_LIST_HEAD(&pal->node);
+}
+EXPORT_SYMBOL_GPL(uwb_pal_init);
+
+/**
+ * uwb_pal_register - register a UWB PAL
+ * @pal: the PAL
+ *
+ * The PAL must be initialized with uwb_pal_init().
+ */
+int uwb_pal_register(struct uwb_pal *pal)
+{
+       struct uwb_rc *rc = pal->rc;
+       int ret;
+
+       if (pal->device) {
+               /* create a link to the uwb_rc in the PAL device's directory. */
+               ret = sysfs_create_link(&pal->device->kobj,
+                                       &rc->uwb_dev.dev.kobj, "uwb_rc");
+               if (ret < 0)
+                       return ret;
+               /* create a link to the PAL in the UWB device's directory. */
+               ret = sysfs_create_link(&rc->uwb_dev.dev.kobj,
+                                       &pal->device->kobj, pal->name);
+               if (ret < 0) {
+                       sysfs_remove_link(&pal->device->kobj, "uwb_rc");
+                       return ret;
+               }
+       }
+
+       pal->debugfs_dir = uwb_dbg_create_pal_dir(pal);
+
+       mutex_lock(&rc->uwb_dev.mutex);
+       list_add(&pal->node, &rc->pals);
+       mutex_unlock(&rc->uwb_dev.mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(uwb_pal_register);
+
+static int find_rc(struct device *dev, const void *data)
+{
+       const struct uwb_rc *target_rc = data;
+       struct uwb_rc *rc = dev_get_drvdata(dev);
+
+       if (rc == NULL) {
+               WARN_ON(1);
+               return 0;
+       }
+       if (rc == target_rc) {
+               if (rc->ready == 0)
+                       return 0;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+/**
+ * Given a radio controller descriptor see if it is registered.
+ *
+ * @returns false if the rc does not exist or is quiescing; true otherwise.
+ */
+static bool uwb_rc_class_device_exists(struct uwb_rc *target_rc)
+{
+       struct device *dev;
+
+       dev = class_find_device(&uwb_rc_class, NULL, target_rc, find_rc);
+
+       put_device(dev);
+
+       return (dev != NULL);
+}
+
+/**
+ * uwb_pal_unregister - unregister a UWB PAL
+ * @pal: the PAL
+ */
+void uwb_pal_unregister(struct uwb_pal *pal)
+{
+       struct uwb_rc *rc = pal->rc;
+
+       uwb_radio_stop(pal);
+
+       mutex_lock(&rc->uwb_dev.mutex);
+       list_del(&pal->node);
+       mutex_unlock(&rc->uwb_dev.mutex);
+
+       debugfs_remove(pal->debugfs_dir);
+
+       if (pal->device) {
+               /* remove link to the PAL in the UWB device's directory. */
+               if (uwb_rc_class_device_exists(rc))
+                       sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
+
+               /* remove link to uwb_rc in the PAL device's directory. */
+               sysfs_remove_link(&pal->device->kobj, "uwb_rc");
+       }
+}
+EXPORT_SYMBOL_GPL(uwb_pal_unregister);
+
+/**
+ * uwb_rc_pal_init - initialize the PAL related parts of a radio controller
+ * @rc: the radio controller
+ */
+void uwb_rc_pal_init(struct uwb_rc *rc)
+{
+       INIT_LIST_HEAD(&rc->pals);
+}
diff --git a/drivers/staging/uwb/radio.c b/drivers/staging/uwb/radio.c
new file mode 100644 (file)
index 0000000..6afb75c
--- /dev/null
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UWB radio (channel) management.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+
+#include "uwb.h"
+#include "uwb-internal.h"
+
+
+static int uwb_radio_select_channel(struct uwb_rc *rc)
+{
+       /*
+        * Default to channel 9 (BG1, TFC1) unless the user has
+        * selected a specific channel or there are no active PALs.
+        */
+       if (rc->active_pals == 0)
+               return -1;
+       if (rc->beaconing_forced)
+               return rc->beaconing_forced;
+       return 9;
+}
+
+
+/*
+ * Notify all active PALs that the channel has changed.
+ */
+static void uwb_radio_channel_changed(struct uwb_rc *rc, int channel)
+{
+       struct uwb_pal *pal;
+
+       list_for_each_entry(pal, &rc->pals, node) {
+               if (pal->channel && channel != pal->channel) {
+                       pal->channel = channel;
+                       if (pal->channel_changed)
+                               pal->channel_changed(pal, pal->channel);
+               }
+       }
+}
+
+/*
+ * Change to a new channel and notify any active PALs of the new
+ * channel.
+ *
+ * When stopping the radio, PALs need to be notified first so they can
+ * terminate any active reservations.
+ */
+static int uwb_radio_change_channel(struct uwb_rc *rc, int channel)
+{
+       int ret = 0;
+       struct device *dev = &rc->uwb_dev.dev;
+
+       dev_dbg(dev, "%s: channel = %d, rc->beaconing = %d\n", __func__,
+               channel, rc->beaconing);
+
+       if (channel == -1)
+               uwb_radio_channel_changed(rc, channel);
+
+       if (channel != rc->beaconing) {
+               if (rc->beaconing != -1 && channel != -1) {
+                       /*
+                        * FIXME: should signal the channel change
+                        * with a Channel Change IE.
+                        */
+                       ret = uwb_radio_change_channel(rc, -1);
+                       if (ret < 0)
+                               return ret;
+               }
+               ret = uwb_rc_beacon(rc, channel, 0);
+       }
+
+       if (channel != -1)
+               uwb_radio_channel_changed(rc, rc->beaconing);
+
+       return ret;
+}
+
+/**
+ * uwb_radio_start - request that the radio be started
+ * @pal: the PAL making the request.
+ *
+ * If the radio is not already active, a suitable channel is selected
+ * and beacons are started.
+ */
+int uwb_radio_start(struct uwb_pal *pal)
+{
+       struct uwb_rc *rc = pal->rc;
+       int ret = 0;
+
+       mutex_lock(&rc->uwb_dev.mutex);
+
+       if (!pal->channel) {
+               pal->channel = -1;
+               rc->active_pals++;
+               ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
+       }
+
+       mutex_unlock(&rc->uwb_dev.mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(uwb_radio_start);
+
+/**
+ * uwb_radio_stop - request that the radio be stopped.
+ * @pal: the PAL making the request.
+ *
+ * Stops the radio if no other PAL is making use of it.
+ */
+void uwb_radio_stop(struct uwb_pal *pal)
+{
+       struct uwb_rc *rc = pal->rc;
+
+       mutex_lock(&rc->uwb_dev.mutex);
+
+       if (pal->channel) {
+               rc->active_pals--;
+               uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
+               pal->channel = 0;
+       }
+
+       mutex_unlock(&rc->uwb_dev.mutex);
+}
+EXPORT_SYMBOL_GPL(uwb_radio_stop);
+
+/*
+ * uwb_radio_force_channel - force a specific channel to be used
+ * @rc: the radio controller.
+ * @channel: the channel to use; -1 to force the radio to stop; 0 to
+ *   use the default channel selection algorithm.
+ */
+int uwb_radio_force_channel(struct uwb_rc *rc, int channel)
+{
+       int ret = 0;
+
+       mutex_lock(&rc->uwb_dev.mutex);
+
+       rc->beaconing_forced = channel;
+       ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
+
+       mutex_unlock(&rc->uwb_dev.mutex);
+       return ret;
+}
+
+/*
+ * uwb_radio_setup - setup the radio manager
+ * @rc: the radio controller.
+ *
+ * The radio controller is reset to ensure it's in a known state
+ * before it's used.
+ */
+int uwb_radio_setup(struct uwb_rc *rc)
+{
+       return uwb_rc_reset(rc);
+}
+
+/*
+ * uwb_radio_reset_state - reset any radio manager state
+ * @rc: the radio controller.
+ *
+ * All internal radio manager state is reset to values corresponding
+ * to a reset radio controller.
+ */
+void uwb_radio_reset_state(struct uwb_rc *rc)
+{
+       struct uwb_pal *pal;
+
+       mutex_lock(&rc->uwb_dev.mutex);
+
+       list_for_each_entry(pal, &rc->pals, node) {
+               if (pal->channel) {
+                       pal->channel = -1;
+                       if (pal->channel_changed)
+                               pal->channel_changed(pal, -1);
+               }
+       }
+
+       rc->beaconing = -1;
+       rc->scanning = -1;
+
+       mutex_unlock(&rc->uwb_dev.mutex);
+}
+
+/*
+ * uwb_radio_shutdown - shutdown the radio manager
+ * @rc: the radio controller.
+ *
+ * The radio controller is reset.
+ */
+void uwb_radio_shutdown(struct uwb_rc *rc)
+{
+       uwb_radio_reset_state(rc);
+       uwb_rc_reset(rc);
+}
diff --git a/drivers/staging/uwb/reset.c b/drivers/staging/uwb/reset.c
new file mode 100644 (file)
index 0000000..8fc7c14
--- /dev/null
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * UWB basic command support and radio reset
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME:
+ *
+ *  - docs
+ *
+ *  - Now we are serializing (using the uwb_dev->mutex) the command
+ *    execution; it should be parallelized as much as possible some
+ *    day.
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+
+#include "uwb-internal.h"
+
+/**
+ * Command result codes (WUSB1.0[T8-69])
+ */
+static
+const char *__strerror[] = {
+       "success",
+       "failure",
+       "hardware failure",
+       "no more slots",
+       "beacon is too large",
+       "invalid parameter",
+       "unsupported power level",
+       "time out (wa) or invalid ie data (whci)",
+       "beacon size exceeded",
+       "cancelled",
+       "invalid state",
+       "invalid size",
+       "ack not received",
+       "no more asie notification",
+};
+
+
+/** Return a string matching the given error code */
+const char *uwb_rc_strerror(unsigned code)
+{
+       if (code == 255)
+               return "time out";
+       if (code >= ARRAY_SIZE(__strerror))
+               return "unknown error";
+       return __strerror[code];
+}
+
+int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
+                    struct uwb_rccb *cmd, size_t cmd_size,
+                    u8 expected_type, u16 expected_event,
+                    uwb_rc_cmd_cb_f cb, void *arg)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_rc_neh *neh;
+       int needtofree = 0;
+       int result;
+
+       uwb_dev_lock(&rc->uwb_dev);     /* Protect against rc->priv being removed */
+       if (rc->priv == NULL) {
+               uwb_dev_unlock(&rc->uwb_dev);
+               return -ESHUTDOWN;
+       }
+
+       if (rc->filter_cmd) {
+               needtofree = rc->filter_cmd(rc, &cmd, &cmd_size);
+               if (needtofree < 0 && needtofree != -ENOANO) {
+                       dev_err(dev, "%s: filter error: %d\n",
+                               cmd_name, needtofree);
+                       uwb_dev_unlock(&rc->uwb_dev);
+                       return needtofree;
+               }
+       }
+
+       neh = uwb_rc_neh_add(rc, cmd, expected_type, expected_event, cb, arg);
+       if (IS_ERR(neh)) {
+               result = PTR_ERR(neh);
+               uwb_dev_unlock(&rc->uwb_dev);
+               goto out;
+       }
+
+       result = rc->cmd(rc, cmd, cmd_size);
+       uwb_dev_unlock(&rc->uwb_dev);
+       if (result < 0)
+               uwb_rc_neh_rm(rc, neh);
+       else
+               uwb_rc_neh_arm(rc, neh);
+       uwb_rc_neh_put(neh);
+out:
+       if (needtofree == 1)
+               kfree(cmd);
+       return result < 0 ? result : 0;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_cmd_async);
+
+struct uwb_rc_cmd_done_params {
+       struct completion completion;
+       struct uwb_rceb *reply;
+       ssize_t reply_size;
+};
+
+static void uwb_rc_cmd_done(struct uwb_rc *rc, void *arg,
+                           struct uwb_rceb *reply, ssize_t reply_size)
+{
+       struct uwb_rc_cmd_done_params *p = (struct uwb_rc_cmd_done_params *)arg;
+
+       if (reply_size > 0) {
+               if (p->reply)
+                       reply_size = min(p->reply_size, reply_size);
+               else
+                       p->reply = kmalloc(reply_size, GFP_ATOMIC);
+
+               if (p->reply)
+                       memcpy(p->reply, reply, reply_size);
+               else
+                       reply_size = -ENOMEM;
+       }
+       p->reply_size = reply_size;
+       complete(&p->completion);
+}
+
+
+/**
+ * Generic function for issuing commands to the Radio Control Interface
+ *
+ * @rc:       UWB Radio Control descriptor
+ * @cmd_name: Name of the command being issued (for error messages)
+ * @cmd:      Pointer to rccb structure containing the command;
+ *            normally you embed this structure as the first member of
+ *            the full command structure.
+ * @cmd_size: Size of the whole command buffer pointed to by @cmd.
+ * @reply:    Pointer to where to store the reply
+ * @reply_size: @reply's size
+ * @expected_type: Expected type in the return event
+ * @expected_event: Expected event code in the return event
+ * @preply:   Here a pointer to where the event data is received will
+ *            be stored. Once done with the data, free with kfree().
+ *
+ * This function is generic; it works for commands that return a fixed
+ * and known size or for commands that return a variable amount of data.
+ *
+ * If a buffer is provided, that is used, although it could be chopped
+ * to the maximum size of the buffer. If the buffer is NULL, then one
+ * be allocated in *preply with the whole contents of the reply.
+ *
+ * @rc needs to be referenced
+ */
+static
+ssize_t __uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
+                    struct uwb_rccb *cmd, size_t cmd_size,
+                    struct uwb_rceb *reply, size_t reply_size,
+                    u8 expected_type, u16 expected_event,
+                    struct uwb_rceb **preply)
+{
+       ssize_t result = 0;
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_rc_cmd_done_params params;
+
+       init_completion(&params.completion);
+       params.reply = reply;
+       params.reply_size = reply_size;
+
+       result = uwb_rc_cmd_async(rc, cmd_name, cmd, cmd_size,
+                                 expected_type, expected_event,
+                                 uwb_rc_cmd_done, &params);
+       if (result)
+               return result;
+
+       wait_for_completion(&params.completion);
+
+       if (preply)
+               *preply = params.reply;
+
+       if (params.reply_size < 0)
+               dev_err(dev, "%s: confirmation event 0x%02x/%04x/%02x "
+                       "reception failed: %d\n", cmd_name,
+                       expected_type, expected_event, cmd->bCommandContext,
+                       (int)params.reply_size);
+       return params.reply_size;
+}
+
+
+/**
+ * Generic function for issuing commands to the Radio Control Interface
+ *
+ * @rc:       UWB Radio Control descriptor
+ * @cmd_name: Name of the command being issued (for error messages)
+ * @cmd:      Pointer to rccb structure containing the command;
+ *            normally you embed this structure as the first member of
+ *            the full command structure.
+ * @cmd_size: Size of the whole command buffer pointed to by @cmd.
+ * @reply:    Pointer to the beginning of the confirmation event
+ *            buffer. Normally bigger than an 'struct hwarc_rceb'.
+ *            You need to fill out reply->bEventType and reply->wEvent (in
+ *            cpu order) as the function will use them to verify the
+ *            confirmation event.
+ * @reply_size: Size of the reply buffer
+ *
+ * The function checks that the length returned in the reply is at
+ * least as big as @reply_size; if not, it will be deemed an error and
+ * -EIO returned.
+ *
+ * @rc needs to be referenced
+ */
+ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
+                  struct uwb_rccb *cmd, size_t cmd_size,
+                  struct uwb_rceb *reply, size_t reply_size)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       ssize_t result;
+
+       result = __uwb_rc_cmd(rc, cmd_name,
+                             cmd, cmd_size, reply, reply_size,
+                             reply->bEventType, reply->wEvent, NULL);
+
+       if (result > 0 && result < reply_size) {
+               dev_err(dev, "%s: not enough data returned for decoding reply "
+                       "(%zu bytes received vs at least %zu needed)\n",
+                       cmd_name, result, reply_size);
+               result = -EIO;
+       }
+       return result;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_cmd);
+
+
+/**
+ * Generic function for issuing commands to the Radio Control
+ * Interface that return an unknown amount of data
+ *
+ * @rc:       UWB Radio Control descriptor
+ * @cmd_name: Name of the command being issued (for error messages)
+ * @cmd:      Pointer to rccb structure containing the command;
+ *            normally you embed this structure as the first member of
+ *            the full command structure.
+ * @cmd_size: Size of the whole command buffer pointed to by @cmd.
+ * @expected_type: Expected type in the return event
+ * @expected_event: Expected event code in the return event
+ * @preply:   Here a pointer to where the event data is received will
+ *            be stored. Once done with the data, free with kfree().
+ *
+ * The function checks that the length returned in the reply is at
+ * least as big as a 'struct uwb_rceb *'; if not, it will be deemed an
+ * error and -EIO returned.
+ *
+ * @rc needs to be referenced
+ */
+ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name,
+                   struct uwb_rccb *cmd, size_t cmd_size,
+                   u8 expected_type, u16 expected_event,
+                   struct uwb_rceb **preply)
+{
+       return __uwb_rc_cmd(rc, cmd_name, cmd, cmd_size, NULL, 0,
+                           expected_type, expected_event, preply);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_vcmd);
+
+
+/**
+ * Reset a UWB Host Controller (and all radio settings)
+ *
+ * @rc:      Host Controller descriptor
+ * @returns: 0 if ok, < 0 errno code on error
+ *
+ * We put the command on kmalloc'ed memory as some arches cannot do
+ * USB from the stack. The reply event is copied from an stage buffer,
+ * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
+ */
+int uwb_rc_reset(struct uwb_rc *rc)
+{
+       int result = -ENOMEM;
+       struct uwb_rc_evt_confirm reply;
+       struct uwb_rccb *cmd;
+       size_t cmd_size = sizeof(*cmd);
+
+       mutex_lock(&rc->uwb_dev.mutex);
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               goto error_kzalloc;
+       cmd->bCommandType = UWB_RC_CET_GENERAL;
+       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET);
+       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+       reply.rceb.wEvent = UWB_RC_CMD_RESET;
+       result = uwb_rc_cmd(rc, "RESET", cmd, cmd_size,
+                           &reply.rceb, sizeof(reply));
+       if (result < 0)
+               goto error_cmd;
+       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+               dev_err(&rc->uwb_dev.dev,
+                       "RESET: command execution failed: %s (%d)\n",
+                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+               result = -EIO;
+       }
+error_cmd:
+       kfree(cmd);
+error_kzalloc:
+       mutex_unlock(&rc->uwb_dev.mutex);
+       return result;
+}
+
+int uwbd_msg_handle_reset(struct uwb_event *evt)
+{
+       struct uwb_rc *rc = evt->rc;
+       int ret;
+
+       dev_info(&rc->uwb_dev.dev, "resetting radio controller\n");
+       ret = rc->reset(rc);
+       if (ret < 0) {
+               dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret);
+               goto error;
+       }
+       return 0;
+error:
+       /* Nothing can be done except try the reset again. Wait a bit
+          to avoid reset loops during probe() or remove(). */
+       msleep(1000);
+       uwb_rc_reset_all(rc);
+       return ret;
+}
+
+/**
+ * uwb_rc_reset_all - request a reset of the radio controller and PALs
+ * @rc: the radio controller of the hardware device to be reset.
+ *
+ * The full hardware reset of the radio controller and all the PALs
+ * will be scheduled.
+ */
+void uwb_rc_reset_all(struct uwb_rc *rc)
+{
+       struct uwb_event *evt;
+
+       evt = kzalloc(sizeof(struct uwb_event), GFP_ATOMIC);
+       if (unlikely(evt == NULL))
+               return;
+
+       evt->rc = __uwb_rc_get(rc);     /* will be put by uwbd's uwbd_event_handle() */
+       evt->ts_jiffies = jiffies;
+       evt->type = UWB_EVT_TYPE_MSG;
+       evt->message = UWB_EVT_MSG_RESET;
+
+       uwbd_event_queue(evt);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_reset_all);
+
+void uwb_rc_pre_reset(struct uwb_rc *rc)
+{
+       rc->stop(rc);
+       uwbd_flush(rc);
+
+       uwb_radio_reset_state(rc);
+       uwb_rsv_remove_all(rc);
+}
+EXPORT_SYMBOL_GPL(uwb_rc_pre_reset);
+
+int uwb_rc_post_reset(struct uwb_rc *rc)
+{
+       int ret;
+
+       ret = rc->start(rc);
+       if (ret)
+               goto out;
+       ret = uwb_rc_mac_addr_set(rc, &rc->uwb_dev.mac_addr);
+       if (ret)
+               goto out;
+       ret = uwb_rc_dev_addr_set(rc, &rc->uwb_dev.dev_addr);
+       if (ret)
+               goto out;
+out:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(uwb_rc_post_reset);
diff --git a/drivers/staging/uwb/rsv.c b/drivers/staging/uwb/rsv.c
new file mode 100644 (file)
index 0000000..f45a04f
--- /dev/null
@@ -0,0 +1,1000 @@
+// 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 <linux/random.h>
+#include <linux/export.h>
+
+#include "uwb.h"
+#include "uwb-internal.h"
+
+static void uwb_rsv_timer(struct timer_list *t);
+
+static const char *rsv_states[] = {
+       [UWB_RSV_STATE_NONE]                 = "none            ",
+       [UWB_RSV_STATE_O_INITIATED]          = "o initiated     ",
+       [UWB_RSV_STATE_O_PENDING]            = "o pending       ",
+       [UWB_RSV_STATE_O_MODIFIED]           = "o modified      ",
+       [UWB_RSV_STATE_O_ESTABLISHED]        = "o established   ",
+       [UWB_RSV_STATE_O_TO_BE_MOVED]        = "o to be moved   ",
+       [UWB_RSV_STATE_O_MOVE_EXPANDING]     = "o move expanding",
+       [UWB_RSV_STATE_O_MOVE_COMBINING]     = "o move combining",
+       [UWB_RSV_STATE_O_MOVE_REDUCING]      = "o move reducing ",
+       [UWB_RSV_STATE_T_ACCEPTED]           = "t accepted      ",
+       [UWB_RSV_STATE_T_CONFLICT]           = "t conflict      ",
+       [UWB_RSV_STATE_T_PENDING]            = "t pending       ",
+       [UWB_RSV_STATE_T_DENIED]             = "t denied        ",
+       [UWB_RSV_STATE_T_RESIZED]            = "t resized       ",
+       [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = "t expanding acc ",
+       [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = "t expanding conf",
+       [UWB_RSV_STATE_T_EXPANDING_PENDING]  = "t expanding pend",
+       [UWB_RSV_STATE_T_EXPANDING_DENIED]   = "t expanding den ",
+};
+
+static const char *rsv_types[] = {
+       [UWB_DRP_TYPE_ALIEN_BP] = "alien-bp",
+       [UWB_DRP_TYPE_HARD]     = "hard",
+       [UWB_DRP_TYPE_SOFT]     = "soft",
+       [UWB_DRP_TYPE_PRIVATE]  = "private",
+       [UWB_DRP_TYPE_PCA]      = "pca",
+};
+
+bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv)
+{
+       static const bool has_two_drp_ies[] = {
+               [UWB_RSV_STATE_O_INITIATED]               = false,
+               [UWB_RSV_STATE_O_PENDING]                 = false,
+               [UWB_RSV_STATE_O_MODIFIED]                = false,
+               [UWB_RSV_STATE_O_ESTABLISHED]             = false,
+               [UWB_RSV_STATE_O_TO_BE_MOVED]             = false,
+               [UWB_RSV_STATE_O_MOVE_COMBINING]          = false,
+               [UWB_RSV_STATE_O_MOVE_REDUCING]           = false,
+               [UWB_RSV_STATE_O_MOVE_EXPANDING]          = true,
+               [UWB_RSV_STATE_T_ACCEPTED]                = false,
+               [UWB_RSV_STATE_T_CONFLICT]                = false,
+               [UWB_RSV_STATE_T_PENDING]                 = false,
+               [UWB_RSV_STATE_T_DENIED]                  = false,
+               [UWB_RSV_STATE_T_RESIZED]                 = false,
+               [UWB_RSV_STATE_T_EXPANDING_ACCEPTED]      = true,
+               [UWB_RSV_STATE_T_EXPANDING_CONFLICT]      = true,
+               [UWB_RSV_STATE_T_EXPANDING_PENDING]       = true,
+               [UWB_RSV_STATE_T_EXPANDING_DENIED]        = true,
+       };
+
+       return has_two_drp_ies[rsv->state];
+}
+
+/**
+ * uwb_rsv_state_str - return a string for a reservation state
+ * @state: the reservation state.
+ */
+const char *uwb_rsv_state_str(enum uwb_rsv_state state)
+{
+       if (state < UWB_RSV_STATE_NONE || state >= UWB_RSV_STATE_LAST)
+               return "unknown";
+       return rsv_states[state];
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_state_str);
+
+/**
+ * uwb_rsv_type_str - return a string for a reservation type
+ * @type: the reservation type
+ */
+const char *uwb_rsv_type_str(enum uwb_drp_type type)
+{
+       if (type < UWB_DRP_TYPE_ALIEN_BP || type > UWB_DRP_TYPE_PCA)
+               return "invalid";
+       return rsv_types[type];
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_type_str);
+
+void uwb_rsv_dump(char *text, struct uwb_rsv *rsv)
+{
+       struct device *dev = &rsv->rc->uwb_dev.dev;
+       struct uwb_dev_addr devaddr;
+       char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
+
+       uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
+       if (rsv->target.type == UWB_RSV_TARGET_DEV)
+               devaddr = rsv->target.dev->dev_addr;
+       else
+               devaddr = rsv->target.devaddr;
+       uwb_dev_addr_print(target, sizeof(target), &devaddr);
+
+       dev_dbg(dev, "rsv %s %s -> %s: %s\n",
+               text, owner, target, uwb_rsv_state_str(rsv->state));
+}
+
+static void uwb_rsv_release(struct kref *kref)
+{
+       struct uwb_rsv *rsv = container_of(kref, struct uwb_rsv, kref);
+
+       kfree(rsv);
+}
+
+void uwb_rsv_get(struct uwb_rsv *rsv)
+{
+       kref_get(&rsv->kref);
+}
+
+void uwb_rsv_put(struct uwb_rsv *rsv)
+{
+       kref_put(&rsv->kref, uwb_rsv_release);
+}
+
+/*
+ * Get a free stream index for a reservation.
+ *
+ * If the target is a DevAddr (e.g., a WUSB cluster reservation) then
+ * the stream is allocated from a pool of per-RC stream indexes,
+ * otherwise a unique stream index for the target is selected.
+ */
+static int uwb_rsv_get_stream(struct uwb_rsv *rsv)
+{
+       struct uwb_rc *rc = rsv->rc;
+       struct device *dev = &rc->uwb_dev.dev;
+       unsigned long *streams_bm;
+       int stream;
+
+       switch (rsv->target.type) {
+       case UWB_RSV_TARGET_DEV:
+               streams_bm = rsv->target.dev->streams;
+               break;
+       case UWB_RSV_TARGET_DEVADDR:
+               streams_bm = rc->uwb_dev.streams;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       stream = find_first_zero_bit(streams_bm, UWB_NUM_STREAMS);
+       if (stream >= UWB_NUM_STREAMS) {
+               dev_err(dev, "%s: no available stream found\n", __func__);
+               return -EBUSY;
+       }
+
+       rsv->stream = stream;
+       set_bit(stream, streams_bm);
+
+       dev_dbg(dev, "get stream %d\n", rsv->stream);
+
+       return 0;
+}
+
+static void uwb_rsv_put_stream(struct uwb_rsv *rsv)
+{
+       struct uwb_rc *rc = rsv->rc;
+       struct device *dev = &rc->uwb_dev.dev;
+       unsigned long *streams_bm;
+
+       switch (rsv->target.type) {
+       case UWB_RSV_TARGET_DEV:
+               streams_bm = rsv->target.dev->streams;
+               break;
+       case UWB_RSV_TARGET_DEVADDR:
+               streams_bm = rc->uwb_dev.streams;
+               break;
+       default:
+               return;
+       }
+
+       clear_bit(rsv->stream, streams_bm);
+
+       dev_dbg(dev, "put stream %d\n", rsv->stream);
+}
+
+void uwb_rsv_backoff_win_timer(struct timer_list *t)
+{
+       struct uwb_drp_backoff_win *bow = from_timer(bow, t, timer);
+       struct uwb_rc *rc = container_of(bow, struct uwb_rc, bow);
+       struct device *dev = &rc->uwb_dev.dev;
+
+       bow->can_reserve_extra_mases = true;
+       if (bow->total_expired <= 4) {
+               bow->total_expired++;
+       } else {
+               /* after 4 backoff window has expired we can exit from
+                * the backoff procedure */
+               bow->total_expired = 0;
+               bow->window = UWB_DRP_BACKOFF_WIN_MIN >> 1;
+       }
+       dev_dbg(dev, "backoff_win_timer total_expired=%d, n=%d\n", bow->total_expired, bow->n);
+
+       /* try to relocate all the "to be moved" relocations */
+       uwb_rsv_handle_drp_avail_change(rc);
+}
+
+void uwb_rsv_backoff_win_increment(struct uwb_rc *rc)
+{
+       struct uwb_drp_backoff_win *bow = &rc->bow;
+       struct device *dev = &rc->uwb_dev.dev;
+       unsigned timeout_us;
+
+       dev_dbg(dev, "backoff_win_increment: window=%d\n", bow->window);
+
+       bow->can_reserve_extra_mases = false;
+
+       if((bow->window << 1) == UWB_DRP_BACKOFF_WIN_MAX)
+               return;
+
+       bow->window <<= 1;
+       bow->n = prandom_u32() & (bow->window - 1);
+       dev_dbg(dev, "new_window=%d, n=%d\n", bow->window, bow->n);
+
+       /* reset the timer associated variables */
+       timeout_us = bow->n * UWB_SUPERFRAME_LENGTH_US;
+       bow->total_expired = 0;
+       mod_timer(&bow->timer, jiffies + usecs_to_jiffies(timeout_us));
+}
+
+static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv)
+{
+       int sframes = UWB_MAX_LOST_BEACONS;
+
+       /*
+        * Multicast reservations can become established within 1
+        * super frame and should not be terminated if no response is
+        * received.
+        */
+       if (rsv->state == UWB_RSV_STATE_NONE) {
+               sframes = 0;
+       } else if (rsv->is_multicast) {
+               if (rsv->state == UWB_RSV_STATE_O_INITIATED
+                   || rsv->state == UWB_RSV_STATE_O_MOVE_EXPANDING
+                   || rsv->state == UWB_RSV_STATE_O_MOVE_COMBINING
+                   || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING)
+                       sframes = 1;
+               if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED)
+                       sframes = 0;
+
+       }
+
+       if (sframes > 0) {
+               /*
+                * Add an additional 2 superframes to account for the
+                * time to send the SET DRP IE command.
+                */
+               unsigned timeout_us = (sframes + 2) * UWB_SUPERFRAME_LENGTH_US;
+               mod_timer(&rsv->timer, jiffies + usecs_to_jiffies(timeout_us));
+       } else
+               del_timer(&rsv->timer);
+}
+
+/*
+ * Update a reservations state, and schedule an update of the
+ * transmitted DRP IEs.
+ */
+static void uwb_rsv_state_update(struct uwb_rsv *rsv,
+                                enum uwb_rsv_state new_state)
+{
+       rsv->state = new_state;
+       rsv->ie_valid = false;
+
+       uwb_rsv_dump("SU", rsv);
+
+       uwb_rsv_stroke_timer(rsv);
+       uwb_rsv_sched_update(rsv->rc);
+}
+
+static void uwb_rsv_callback(struct uwb_rsv *rsv)
+{
+       if (rsv->callback)
+               rsv->callback(rsv);
+}
+
+void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state)
+{
+       struct uwb_rsv_move *mv = &rsv->mv;
+
+       if (rsv->state == new_state) {
+               switch (rsv->state) {
+               case UWB_RSV_STATE_O_ESTABLISHED:
+               case UWB_RSV_STATE_O_MOVE_EXPANDING:
+               case UWB_RSV_STATE_O_MOVE_COMBINING:
+               case UWB_RSV_STATE_O_MOVE_REDUCING:
+               case UWB_RSV_STATE_T_ACCEPTED:
+               case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
+               case UWB_RSV_STATE_T_RESIZED:
+               case UWB_RSV_STATE_NONE:
+                       uwb_rsv_stroke_timer(rsv);
+                       break;
+               default:
+                       /* Expecting a state transition so leave timer
+                          as-is. */
+                       break;
+               }
+               return;
+       }
+
+       uwb_rsv_dump("SC", rsv);
+
+       switch (new_state) {
+       case UWB_RSV_STATE_NONE:
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE);
+               uwb_rsv_remove(rsv);
+               uwb_rsv_callback(rsv);
+               break;
+       case UWB_RSV_STATE_O_INITIATED:
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_INITIATED);
+               break;
+       case UWB_RSV_STATE_O_PENDING:
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_PENDING);
+               break;
+       case UWB_RSV_STATE_O_MODIFIED:
+               /* in the companion there are the MASes to drop */
+               bitmap_andnot(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS);
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MODIFIED);
+               break;
+       case UWB_RSV_STATE_O_ESTABLISHED:
+               if (rsv->state == UWB_RSV_STATE_O_MODIFIED
+                   || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING) {
+                       uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
+                       rsv->needs_release_companion_mas = false;
+               }
+               uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+               uwb_rsv_callback(rsv);
+               break;
+       case UWB_RSV_STATE_O_MOVE_EXPANDING:
+               rsv->needs_release_companion_mas = true;
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
+               break;
+       case UWB_RSV_STATE_O_MOVE_COMBINING:
+               rsv->needs_release_companion_mas = false;
+               uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas);
+               bitmap_or(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS);
+               rsv->mas.safe   += mv->companion_mas.safe;
+               rsv->mas.unsafe += mv->companion_mas.unsafe;
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
+               break;
+       case UWB_RSV_STATE_O_MOVE_REDUCING:
+               bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS);
+               rsv->needs_release_companion_mas = true;
+               rsv->mas.safe   = mv->final_mas.safe;
+               rsv->mas.unsafe = mv->final_mas.unsafe;
+               bitmap_copy(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS);
+               bitmap_copy(rsv->mas.unsafe_bm, mv->final_mas.unsafe_bm, UWB_NUM_MAS);
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
+               break;
+       case UWB_RSV_STATE_T_ACCEPTED:
+       case UWB_RSV_STATE_T_RESIZED:
+               rsv->needs_release_companion_mas = false;
+               uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_ACCEPTED);
+               uwb_rsv_callback(rsv);
+               break;
+       case UWB_RSV_STATE_T_DENIED:
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_DENIED);
+               break;
+       case UWB_RSV_STATE_T_CONFLICT:
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_CONFLICT);
+               break;
+       case UWB_RSV_STATE_T_PENDING:
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_PENDING);
+               break;
+       case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
+               rsv->needs_release_companion_mas = true;
+               uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas);
+               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
+               break;
+       default:
+               dev_err(&rsv->rc->uwb_dev.dev, "unhandled state: %s (%d)\n",
+                       uwb_rsv_state_str(new_state), new_state);
+       }
+}
+
+static void uwb_rsv_handle_timeout_work(struct work_struct *work)
+{
+       struct uwb_rsv *rsv = container_of(work, struct uwb_rsv,
+                                          handle_timeout_work);
+       struct uwb_rc *rc = rsv->rc;
+
+       mutex_lock(&rc->rsvs_mutex);
+
+       uwb_rsv_dump("TO", rsv);
+
+       switch (rsv->state) {
+       case UWB_RSV_STATE_O_INITIATED:
+               if (rsv->is_multicast) {
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+                       goto unlock;
+               }
+               break;
+       case UWB_RSV_STATE_O_MOVE_EXPANDING:
+               if (rsv->is_multicast) {
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
+                       goto unlock;
+               }
+               break;
+       case UWB_RSV_STATE_O_MOVE_COMBINING:
+               if (rsv->is_multicast) {
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
+                       goto unlock;
+               }
+               break;
+       case UWB_RSV_STATE_O_MOVE_REDUCING:
+               if (rsv->is_multicast) {
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+                       goto unlock;
+               }
+               break;
+       case UWB_RSV_STATE_O_ESTABLISHED:
+               if (rsv->is_multicast)
+                       goto unlock;
+               break;
+       case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
+               /*
+                * The time out could be for the main or of the
+                * companion DRP, assume it's for the companion and
+                * drop that first.  A further time out is required to
+                * drop the main.
+                */
+               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
+               uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
+               goto unlock;
+       case UWB_RSV_STATE_NONE:
+               goto unlock;
+       default:
+               break;
+       }
+
+       uwb_rsv_remove(rsv);
+
+unlock:
+       mutex_unlock(&rc->rsvs_mutex);
+}
+
+static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc)
+{
+       struct uwb_rsv *rsv;
+
+       rsv = kzalloc(sizeof(struct uwb_rsv), GFP_KERNEL);
+       if (!rsv)
+               return NULL;
+
+       INIT_LIST_HEAD(&rsv->rc_node);
+       INIT_LIST_HEAD(&rsv->pal_node);
+       kref_init(&rsv->kref);
+       timer_setup(&rsv->timer, uwb_rsv_timer, 0);
+
+       rsv->rc = rc;
+       INIT_WORK(&rsv->handle_timeout_work, uwb_rsv_handle_timeout_work);
+
+       return rsv;
+}
+
+/**
+ * uwb_rsv_create - allocate and initialize a UWB reservation structure
+ * @rc: the radio controller
+ * @cb: callback to use when the reservation completes or terminates
+ * @pal_priv: data private to the PAL to be passed in the callback
+ *
+ * The callback is called when the state of the reservation changes from:
+ *
+ *   - pending to accepted
+ *   - pending to denined
+ *   - accepted to terminated
+ *   - pending to terminated
+ */
+struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb, void *pal_priv)
+{
+       struct uwb_rsv *rsv;
+
+       rsv = uwb_rsv_alloc(rc);
+       if (!rsv)
+               return NULL;
+
+       rsv->callback = cb;
+       rsv->pal_priv = pal_priv;
+
+       return rsv;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_create);
+
+void uwb_rsv_remove(struct uwb_rsv *rsv)
+{
+       uwb_rsv_dump("RM", rsv);
+
+       if (rsv->state != UWB_RSV_STATE_NONE)
+               uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+
+       if (rsv->needs_release_companion_mas)
+               uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
+       uwb_drp_avail_release(rsv->rc, &rsv->mas);
+
+       if (uwb_rsv_is_owner(rsv))
+               uwb_rsv_put_stream(rsv);
+
+       uwb_dev_put(rsv->owner);
+       if (rsv->target.type == UWB_RSV_TARGET_DEV)
+               uwb_dev_put(rsv->target.dev);
+
+       list_del_init(&rsv->rc_node);
+       uwb_rsv_put(rsv);
+}
+
+/**
+ * uwb_rsv_destroy - free a UWB reservation structure
+ * @rsv: the reservation to free
+ *
+ * The reservation must already be terminated.
+ */
+void uwb_rsv_destroy(struct uwb_rsv *rsv)
+{
+       uwb_rsv_put(rsv);
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_destroy);
+
+/**
+ * usb_rsv_establish - start a reservation establishment
+ * @rsv: the reservation
+ *
+ * The PAL should fill in @rsv's owner, target, type, max_mas,
+ * min_mas, max_interval and is_multicast fields.  If the target is a
+ * uwb_dev it must be referenced.
+ *
+ * The reservation's callback will be called when the reservation is
+ * accepted, denied or times out.
+ */
+int uwb_rsv_establish(struct uwb_rsv *rsv)
+{
+       struct uwb_rc *rc = rsv->rc;
+       struct uwb_mas_bm available;
+       struct device *dev = &rc->uwb_dev.dev;
+       int ret;
+
+       mutex_lock(&rc->rsvs_mutex);
+       ret = uwb_rsv_get_stream(rsv);
+       if (ret) {
+               dev_err(dev, "%s: uwb_rsv_get_stream failed: %d\n",
+                       __func__, ret);
+               goto out;
+       }
+
+       rsv->tiebreaker = prandom_u32() & 1;
+       /* get available mas bitmap */
+       uwb_drp_available(rc, &available);
+
+       ret = uwb_rsv_find_best_allocation(rsv, &available, &rsv->mas);
+       if (ret == UWB_RSV_ALLOC_NOT_FOUND) {
+               ret = -EBUSY;
+               uwb_rsv_put_stream(rsv);
+               dev_err(dev, "%s: uwb_rsv_find_best_allocation failed: %d\n",
+                       __func__, ret);
+               goto out;
+       }
+
+       ret = uwb_drp_avail_reserve_pending(rc, &rsv->mas);
+       if (ret != 0) {
+               uwb_rsv_put_stream(rsv);
+               dev_err(dev, "%s: uwb_drp_avail_reserve_pending failed: %d\n",
+                       __func__, ret);
+               goto out;
+       }
+
+       uwb_rsv_get(rsv);
+       list_add_tail(&rsv->rc_node, &rc->reservations);
+       rsv->owner = &rc->uwb_dev;
+       uwb_dev_get(rsv->owner);
+       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_INITIATED);
+out:
+       mutex_unlock(&rc->rsvs_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_establish);
+
+/**
+ * uwb_rsv_modify - modify an already established reservation
+ * @rsv: the reservation to modify
+ * @max_mas: new maximum MAS to reserve
+ * @min_mas: new minimum MAS to reserve
+ * @max_interval: new max_interval to use
+ *
+ * FIXME: implement this once there are PALs that use it.
+ */
+int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int max_interval)
+{
+       return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_modify);
+
+/*
+ * move an already established reservation (rc->rsvs_mutex must to be
+ * taken when tis function is called)
+ */
+int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available)
+{
+       struct uwb_rc *rc = rsv->rc;
+       struct uwb_drp_backoff_win *bow = &rc->bow;
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_rsv_move *mv;
+       int ret = 0;
+
+       if (bow->can_reserve_extra_mases == false)
+               return -EBUSY;
+
+       mv = &rsv->mv;
+
+       if (uwb_rsv_find_best_allocation(rsv, available, &mv->final_mas) == UWB_RSV_ALLOC_FOUND) {
+
+               if (!bitmap_equal(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS)) {
+                       /* We want to move the reservation */
+                       bitmap_andnot(mv->companion_mas.bm, mv->final_mas.bm, rsv->mas.bm, UWB_NUM_MAS);
+                       uwb_drp_avail_reserve_pending(rc, &mv->companion_mas);
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
+               }
+       } else {
+               dev_dbg(dev, "new allocation not found\n");
+       }
+
+       return ret;
+}
+
+/* It will try to move every reservation in state O_ESTABLISHED giving
+ * to the MAS allocator algorithm an availability that is the real one
+ * plus the allocation already established from the reservation. */
+void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc)
+{
+       struct uwb_drp_backoff_win *bow = &rc->bow;
+       struct uwb_rsv *rsv;
+       struct uwb_mas_bm mas;
+
+       if (bow->can_reserve_extra_mases == false)
+               return;
+
+       list_for_each_entry(rsv, &rc->reservations, rc_node) {
+               if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED ||
+                   rsv->state == UWB_RSV_STATE_O_TO_BE_MOVED) {
+                       uwb_drp_available(rc, &mas);
+                       bitmap_or(mas.bm, mas.bm, rsv->mas.bm, UWB_NUM_MAS);
+                       uwb_rsv_try_move(rsv, &mas);
+               }
+       }
+
+}
+
+/**
+ * uwb_rsv_terminate - terminate an established reservation
+ * @rsv: the reservation to terminate
+ *
+ * A reservation is terminated by removing the DRP IE from the beacon,
+ * the other end will consider the reservation to be terminated when
+ * it does not see the DRP IE for at least mMaxLostBeacons.
+ *
+ * If applicable, the reference to the target uwb_dev will be released.
+ */
+void uwb_rsv_terminate(struct uwb_rsv *rsv)
+{
+       struct uwb_rc *rc = rsv->rc;
+
+       mutex_lock(&rc->rsvs_mutex);
+
+       if (rsv->state != UWB_RSV_STATE_NONE)
+               uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+
+       mutex_unlock(&rc->rsvs_mutex);
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_terminate);
+
+/**
+ * uwb_rsv_accept - accept a new reservation from a peer
+ * @rsv:      the reservation
+ * @cb:       call back for reservation changes
+ * @pal_priv: data to be passed in the above call back
+ *
+ * Reservation requests from peers are denied unless a PAL accepts it
+ * by calling this function.
+ *
+ * The PAL call uwb_rsv_destroy() for all accepted reservations before
+ * calling uwb_pal_unregister().
+ */
+void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv)
+{
+       uwb_rsv_get(rsv);
+
+       rsv->callback = cb;
+       rsv->pal_priv = pal_priv;
+       rsv->state    = UWB_RSV_STATE_T_ACCEPTED;
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_accept);
+
+/*
+ * Is a received DRP IE for this reservation?
+ */
+static bool uwb_rsv_match(struct uwb_rsv *rsv, struct uwb_dev *src,
+                         struct uwb_ie_drp *drp_ie)
+{
+       struct uwb_dev_addr *rsv_src;
+       int stream;
+
+       stream = uwb_ie_drp_stream_index(drp_ie);
+
+       if (rsv->stream != stream)
+               return false;
+
+       switch (rsv->target.type) {
+       case UWB_RSV_TARGET_DEVADDR:
+               return rsv->stream == stream;
+       case UWB_RSV_TARGET_DEV:
+               if (uwb_ie_drp_owner(drp_ie))
+                       rsv_src = &rsv->owner->dev_addr;
+               else
+                       rsv_src = &rsv->target.dev->dev_addr;
+               return uwb_dev_addr_cmp(&src->dev_addr, rsv_src) == 0;
+       }
+       return false;
+}
+
+static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc,
+                                         struct uwb_dev *src,
+                                         struct uwb_ie_drp *drp_ie)
+{
+       struct uwb_rsv *rsv;
+       struct uwb_pal *pal;
+       enum uwb_rsv_state state;
+
+       rsv = uwb_rsv_alloc(rc);
+       if (!rsv)
+               return NULL;
+
+       rsv->rc          = rc;
+       rsv->owner       = src;
+       uwb_dev_get(rsv->owner);
+       rsv->target.type = UWB_RSV_TARGET_DEV;
+       rsv->target.dev  = &rc->uwb_dev;
+       uwb_dev_get(&rc->uwb_dev);
+       rsv->type        = uwb_ie_drp_type(drp_ie);
+       rsv->stream      = uwb_ie_drp_stream_index(drp_ie);
+       uwb_drp_ie_to_bm(&rsv->mas, drp_ie);
+
+       /*
+        * See if any PALs are interested in this reservation. If not,
+        * deny the request.
+        */
+       rsv->state = UWB_RSV_STATE_T_DENIED;
+       mutex_lock(&rc->uwb_dev.mutex);
+       list_for_each_entry(pal, &rc->pals, node) {
+               if (pal->new_rsv)
+                       pal->new_rsv(pal, rsv);
+               if (rsv->state == UWB_RSV_STATE_T_ACCEPTED)
+                       break;
+       }
+       mutex_unlock(&rc->uwb_dev.mutex);
+
+       list_add_tail(&rsv->rc_node, &rc->reservations);
+       state = rsv->state;
+       rsv->state = UWB_RSV_STATE_NONE;
+
+       /* FIXME: do something sensible here */
+       if (state == UWB_RSV_STATE_T_ACCEPTED
+           && uwb_drp_avail_reserve_pending(rc, &rsv->mas) == -EBUSY) {
+               /* FIXME: do something sensible here */
+       } else {
+               uwb_rsv_set_state(rsv, state);
+       }
+
+       return rsv;
+}
+
+/**
+ * uwb_rsv_get_usable_mas - get the bitmap of the usable MAS of a reservations
+ * @rsv: the reservation.
+ * @mas: returns the available MAS.
+ *
+ * The usable MAS of a reservation may be less than the negotiated MAS
+ * if alien BPs are present.
+ */
+void uwb_rsv_get_usable_mas(struct uwb_rsv *rsv, struct uwb_mas_bm *mas)
+{
+       bitmap_zero(mas->bm, UWB_NUM_MAS);
+       bitmap_andnot(mas->bm, rsv->mas.bm, rsv->rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
+}
+EXPORT_SYMBOL_GPL(uwb_rsv_get_usable_mas);
+
+/**
+ * uwb_rsv_find - find a reservation for a received DRP IE.
+ * @rc: the radio controller
+ * @src: source of the DRP IE
+ * @drp_ie: the DRP IE
+ *
+ * If the reservation cannot be found and the DRP IE is from a peer
+ * attempting to establish a new reservation, create a new reservation
+ * and add it to the list.
+ */
+struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
+                            struct uwb_ie_drp *drp_ie)
+{
+       struct uwb_rsv *rsv;
+
+       list_for_each_entry(rsv, &rc->reservations, rc_node) {
+               if (uwb_rsv_match(rsv, src, drp_ie))
+                       return rsv;
+       }
+
+       if (uwb_ie_drp_owner(drp_ie))
+               return uwb_rsv_new_target(rc, src, drp_ie);
+
+       return NULL;
+}
+
+/*
+ * Go through all the reservations and check for timeouts and (if
+ * necessary) update their DRP IEs.
+ *
+ * FIXME: look at building the SET_DRP_IE command here rather than
+ * having to rescan the list in uwb_rc_send_all_drp_ie().
+ */
+static bool uwb_rsv_update_all(struct uwb_rc *rc)
+{
+       struct uwb_rsv *rsv, *t;
+       bool ie_updated = false;
+
+       list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
+               if (!rsv->ie_valid) {
+                       uwb_drp_ie_update(rsv);
+                       ie_updated = true;
+               }
+       }
+
+       return ie_updated;
+}
+
+void uwb_rsv_queue_update(struct uwb_rc *rc)
+{
+       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
+
+       queue_delayed_work(rc->rsv_workq, &rc->rsv_update_work, usecs_to_jiffies(delay_us));
+}
+
+/**
+ * uwb_rsv_sched_update - schedule an update of the DRP IEs
+ * @rc: the radio controller.
+ *
+ * To improve performance and ensure correctness with [ECMA-368] the
+ * number of SET-DRP-IE commands that are done are limited.
+ *
+ * DRP IEs update come from two sources: DRP events from the hardware
+ * which all occur at the beginning of the superframe ('syncronous'
+ * events) and reservation establishment/termination requests from
+ * PALs or timers ('asynchronous' events).
+ *
+ * A delayed work ensures that all the synchronous events result in
+ * one SET-DRP-IE command.
+ *
+ * Additional logic (the set_drp_ie_pending and rsv_updated_postponed
+ * flags) will prevent an asynchrous event starting a SET-DRP-IE
+ * command if one is currently awaiting a response.
+ *
+ * FIXME: this does leave a window where an asynchrous event can delay
+ * the SET-DRP-IE for a synchronous event by one superframe.
+ */
+void uwb_rsv_sched_update(struct uwb_rc *rc)
+{
+       spin_lock_irq(&rc->rsvs_lock);
+       if (!delayed_work_pending(&rc->rsv_update_work)) {
+               if (rc->set_drp_ie_pending > 0) {
+                       rc->set_drp_ie_pending++;
+                       goto unlock;
+               }
+               uwb_rsv_queue_update(rc);
+       }
+unlock:
+       spin_unlock_irq(&rc->rsvs_lock);
+}
+
+/*
+ * Update DRP IEs and, if necessary, the DRP Availability IE and send
+ * the updated IEs to the radio controller.
+ */
+static void uwb_rsv_update_work(struct work_struct *work)
+{
+       struct uwb_rc *rc = container_of(work, struct uwb_rc,
+                                        rsv_update_work.work);
+       bool ie_updated;
+
+       mutex_lock(&rc->rsvs_mutex);
+
+       ie_updated = uwb_rsv_update_all(rc);
+
+       if (!rc->drp_avail.ie_valid) {
+               uwb_drp_avail_ie_update(rc);
+               ie_updated = true;
+       }
+
+       if (ie_updated && (rc->set_drp_ie_pending == 0))
+               uwb_rc_send_all_drp_ie(rc);
+
+       mutex_unlock(&rc->rsvs_mutex);
+}
+
+static void uwb_rsv_alien_bp_work(struct work_struct *work)
+{
+       struct uwb_rc *rc = container_of(work, struct uwb_rc,
+                                        rsv_alien_bp_work.work);
+       struct uwb_rsv *rsv;
+
+       mutex_lock(&rc->rsvs_mutex);
+
+       list_for_each_entry(rsv, &rc->reservations, rc_node) {
+               if (rsv->type != UWB_DRP_TYPE_ALIEN_BP) {
+                       uwb_rsv_callback(rsv);
+               }
+       }
+
+       mutex_unlock(&rc->rsvs_mutex);
+}
+
+static void uwb_rsv_timer(struct timer_list *t)
+{
+       struct uwb_rsv *rsv = from_timer(rsv, t, timer);
+
+       queue_work(rsv->rc->rsv_workq, &rsv->handle_timeout_work);
+}
+
+/**
+ * uwb_rsv_remove_all - remove all reservations
+ * @rc: the radio controller
+ *
+ * A DRP IE update is not done.
+ */
+void uwb_rsv_remove_all(struct uwb_rc *rc)
+{
+       struct uwb_rsv *rsv, *t;
+
+       mutex_lock(&rc->rsvs_mutex);
+       list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
+               if (rsv->state != UWB_RSV_STATE_NONE)
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
+               del_timer_sync(&rsv->timer);
+       }
+       /* Cancel any postponed update. */
+       rc->set_drp_ie_pending = 0;
+       mutex_unlock(&rc->rsvs_mutex);
+
+       cancel_delayed_work_sync(&rc->rsv_update_work);
+       flush_workqueue(rc->rsv_workq);
+
+       mutex_lock(&rc->rsvs_mutex);
+       list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
+               uwb_rsv_remove(rsv);
+       }
+       mutex_unlock(&rc->rsvs_mutex);
+}
+
+void uwb_rsv_init(struct uwb_rc *rc)
+{
+       INIT_LIST_HEAD(&rc->reservations);
+       INIT_LIST_HEAD(&rc->cnflt_alien_list);
+       mutex_init(&rc->rsvs_mutex);
+       spin_lock_init(&rc->rsvs_lock);
+       INIT_DELAYED_WORK(&rc->rsv_update_work, uwb_rsv_update_work);
+       INIT_DELAYED_WORK(&rc->rsv_alien_bp_work, uwb_rsv_alien_bp_work);
+       rc->bow.can_reserve_extra_mases = true;
+       rc->bow.total_expired = 0;
+       rc->bow.window = UWB_DRP_BACKOFF_WIN_MIN >> 1;
+       timer_setup(&rc->bow.timer, uwb_rsv_backoff_win_timer, 0);
+
+       bitmap_complement(rc->uwb_dev.streams, rc->uwb_dev.streams, UWB_NUM_STREAMS);
+}
+
+int uwb_rsv_setup(struct uwb_rc *rc)
+{
+       char name[16];
+
+       snprintf(name, sizeof(name), "%s_rsvd", dev_name(&rc->uwb_dev.dev));
+       rc->rsv_workq = create_singlethread_workqueue(name);
+       if (rc->rsv_workq == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void uwb_rsv_cleanup(struct uwb_rc *rc)
+{
+       uwb_rsv_remove_all(rc);
+       destroy_workqueue(rc->rsv_workq);
+}
diff --git a/drivers/staging/uwb/scan.c b/drivers/staging/uwb/scan.c
new file mode 100644 (file)
index 0000000..ffc3f45
--- /dev/null
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Scanning management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ * FIXME: there are issues here on how BEACON and SCAN on USB RCI deal
+ *        with each other. Currently seems that START_BEACON while
+ *        SCAN_ONLY will cancel the scan, so we need to update the
+ *        state here. Clarification request sent by email on
+ *        10/05/2005.
+ *        10/28/2005 No clear answer heard--maybe we'll hack the API
+ *                   so that when we start beaconing, if the HC is
+ *                   scanning in a mode not compatible with beaconing
+ *                   we just fail.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include "uwb-internal.h"
+
+
+/**
+ * Start/stop scanning in a radio controller
+ *
+ * @rc:      UWB Radio Controller
+ * @channel: Channel to scan; encodings in WUSB1.0[Table 5.12]
+ * @type:    Type of scanning to do.
+ * @bpst_offset: value at which to start scanning (if type ==
+ *                UWB_SCAN_ONLY_STARTTIME)
+ * @returns: 0 if ok, < 0 errno code on error
+ *
+ * We put the command on kmalloc'ed memory as some arches cannot do
+ * USB from the stack. The reply event is copied from an stage buffer,
+ * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
+ */
+int uwb_rc_scan(struct uwb_rc *rc,
+               unsigned channel, enum uwb_scan_type type,
+               unsigned bpst_offset)
+{
+       int result;
+       struct uwb_rc_cmd_scan *cmd;
+       struct uwb_rc_evt_confirm reply;
+
+       result = -ENOMEM;
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               goto error_kzalloc;
+       mutex_lock(&rc->uwb_dev.mutex);
+       cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
+       cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SCAN);
+       cmd->bChannelNumber = channel;
+       cmd->bScanState = type;
+       cmd->wStartTime = cpu_to_le16(bpst_offset);
+       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
+       reply.rceb.wEvent = UWB_RC_CMD_SCAN;
+       result = uwb_rc_cmd(rc, "SCAN", &cmd->rccb, sizeof(*cmd),
+                           &reply.rceb, sizeof(reply));
+       if (result < 0)
+               goto error_cmd;
+       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
+               dev_err(&rc->uwb_dev.dev,
+                       "SCAN: command execution failed: %s (%d)\n",
+                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
+               result = -EIO;
+               goto error_cmd;
+       }
+       rc->scanning = channel;
+       rc->scan_type = type;
+error_cmd:
+       mutex_unlock(&rc->uwb_dev.mutex);
+       kfree(cmd);
+error_kzalloc:
+       return result;
+}
+
+/*
+ * Print scanning state
+ */
+static ssize_t uwb_rc_scan_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;
+       ssize_t result;
+
+       mutex_lock(&rc->uwb_dev.mutex);
+       result = sprintf(buf, "%d %d\n", rc->scanning, rc->scan_type);
+       mutex_unlock(&rc->uwb_dev.mutex);
+       return result;
+}
+
+/*
+ *
+ */
+static ssize_t uwb_rc_scan_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;
+       unsigned channel;
+       unsigned type;
+       unsigned bpst_offset = 0;
+       ssize_t result = -EINVAL;
+
+       result = sscanf(buf, "%u %u %u\n", &channel, &type, &bpst_offset);
+       if (result >= 2 && type < UWB_SCAN_TOP)
+               result = uwb_rc_scan(rc, channel, type, bpst_offset);
+
+       return result < 0 ? result : size;
+}
+
+/** Radio Control sysfs interface (declaration) */
+DEVICE_ATTR(scan, S_IRUGO | S_IWUSR, uwb_rc_scan_show, uwb_rc_scan_store);
diff --git a/drivers/staging/uwb/umc-bus.c b/drivers/staging/uwb/umc-bus.c
new file mode 100644 (file)
index 0000000..8b931f6
--- /dev/null
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Bus for UWB Multi-interface Controller capabilities.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include "include/umc.h"
+
+static int umc_bus_pre_reset_helper(struct device *dev, void *data)
+{
+       int ret = 0;
+
+       if (dev->driver) {
+               struct umc_dev *umc = to_umc_dev(dev);
+               struct umc_driver *umc_drv = to_umc_driver(dev->driver);
+
+               if (umc_drv->pre_reset)
+                       ret = umc_drv->pre_reset(umc);
+               else
+                       device_release_driver(dev);
+       }
+       return ret;
+}
+
+static int umc_bus_post_reset_helper(struct device *dev, void *data)
+{
+       int ret = 0;
+
+       if (dev->driver) {
+               struct umc_dev *umc = to_umc_dev(dev);
+               struct umc_driver *umc_drv = to_umc_driver(dev->driver);
+
+               if (umc_drv->post_reset)
+                       ret = umc_drv->post_reset(umc);
+       } else
+               ret = device_attach(dev);
+
+       return ret;
+}
+
+/**
+ * umc_controller_reset - reset the whole UMC controller
+ * @umc: the UMC device for the radio controller.
+ *
+ * Drivers or all capabilities of the controller will have their
+ * pre_reset methods called or be unbound from their device.  Then all
+ * post_reset methods will be called or the drivers will be rebound.
+ *
+ * Radio controllers must provide pre_reset and post_reset methods and
+ * reset the hardware in their start method.
+ *
+ * If this is called while a probe() or remove() is in progress it
+ * will return -EAGAIN and not perform the reset.
+ */
+int umc_controller_reset(struct umc_dev *umc)
+{
+       struct device *parent = umc->dev.parent;
+       int ret = 0;
+
+       if (!device_trylock(parent))
+               return -EAGAIN;
+       ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper);
+       if (ret >= 0)
+               ret = device_for_each_child(parent, parent, umc_bus_post_reset_helper);
+       device_unlock(parent);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(umc_controller_reset);
+
+/**
+ * umc_match_pci_id - match a UMC driver to a UMC device's parent PCI device.
+ * @umc_drv: umc driver with match_data pointing to a zero-terminated
+ * table of pci_device_id's.
+ * @umc: umc device whose parent is to be matched.
+ */
+int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc)
+{
+       const struct pci_device_id *id_table = umc_drv->match_data;
+       struct pci_dev *pci;
+
+       if (!dev_is_pci(umc->dev.parent))
+               return 0;
+
+       pci = to_pci_dev(umc->dev.parent);
+       return pci_match_id(id_table, pci) != NULL;
+}
+EXPORT_SYMBOL_GPL(umc_match_pci_id);
+
+static int umc_bus_rescan_helper(struct device *dev, void *data)
+{
+       int ret = 0;
+
+       if (!dev->driver)
+               ret = device_attach(dev);
+
+       return ret;
+}
+
+static void umc_bus_rescan(struct device *parent)
+{
+       int err;
+
+       /*
+        * We can't use bus_rescan_devices() here as it deadlocks when
+        * it tries to retake the dev->parent semaphore.
+        */
+       err = device_for_each_child(parent, NULL, umc_bus_rescan_helper);
+       if (err < 0)
+               printk(KERN_WARNING "%s: rescan of bus failed: %d\n",
+                      KBUILD_MODNAME, err);
+}
+
+static int umc_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct umc_dev *umc = to_umc_dev(dev);
+       struct umc_driver *umc_driver = to_umc_driver(drv);
+
+       if (umc->cap_id == umc_driver->cap_id) {
+               if (umc_driver->match)
+                       return umc_driver->match(umc_driver, umc);
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+static int umc_device_probe(struct device *dev)
+{
+       struct umc_dev *umc;
+       struct umc_driver *umc_driver;
+       int err;
+
+       umc_driver = to_umc_driver(dev->driver);
+       umc = to_umc_dev(dev);
+
+       get_device(dev);
+       err = umc_driver->probe(umc);
+       if (err)
+               put_device(dev);
+       else
+               umc_bus_rescan(dev->parent);
+
+       return err;
+}
+
+static int umc_device_remove(struct device *dev)
+{
+       struct umc_dev *umc;
+       struct umc_driver *umc_driver;
+
+       umc_driver = to_umc_driver(dev->driver);
+       umc = to_umc_dev(dev);
+
+       umc_driver->remove(umc);
+       put_device(dev);
+       return 0;
+}
+
+static ssize_t capability_id_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct umc_dev *umc = to_umc_dev(dev);
+
+       return sprintf(buf, "0x%02x\n", umc->cap_id);
+}
+static DEVICE_ATTR_RO(capability_id);
+
+static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct umc_dev *umc = to_umc_dev(dev);
+
+       return sprintf(buf, "0x%04x\n", umc->version);
+}
+static DEVICE_ATTR_RO(version);
+
+static struct attribute *umc_dev_attrs[] = {
+       &dev_attr_capability_id.attr,
+       &dev_attr_version.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(umc_dev);
+
+struct bus_type umc_bus_type = {
+       .name           = "umc",
+       .match          = umc_bus_match,
+       .probe          = umc_device_probe,
+       .remove         = umc_device_remove,
+       .dev_groups     = umc_dev_groups,
+};
+EXPORT_SYMBOL_GPL(umc_bus_type);
+
+static int __init umc_bus_init(void)
+{
+       return bus_register(&umc_bus_type);
+}
+module_init(umc_bus_init);
+
+static void __exit umc_bus_exit(void)
+{
+       bus_unregister(&umc_bus_type);
+}
+module_exit(umc_bus_exit);
+
+MODULE_DESCRIPTION("UWB Multi-interface Controller capability bus");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/umc-dev.c b/drivers/staging/uwb/umc-dev.c
new file mode 100644 (file)
index 0000000..0c71caa
--- /dev/null
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UWB Multi-interface Controller device management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include "include/umc.h"
+
+static void umc_device_release(struct device *dev)
+{
+       struct umc_dev *umc = to_umc_dev(dev);
+
+       kfree(umc);
+}
+
+/**
+ * umc_device_create - allocate a child UMC device
+ * @parent: parent of the new UMC device.
+ * @n:      index of the new device.
+ *
+ * The new UMC device will have a bus ID of the parent with '-n'
+ * appended.
+ */
+struct umc_dev *umc_device_create(struct device *parent, int n)
+{
+       struct umc_dev *umc;
+
+       umc = kzalloc(sizeof(struct umc_dev), GFP_KERNEL);
+       if (umc) {
+               dev_set_name(&umc->dev, "%s-%d", dev_name(parent), n);
+               umc->dev.parent  = parent;
+               umc->dev.bus     = &umc_bus_type;
+               umc->dev.release = umc_device_release;
+
+               umc->dev.dma_mask = parent->dma_mask;
+       }
+       return umc;
+}
+EXPORT_SYMBOL_GPL(umc_device_create);
+
+/**
+ * umc_device_register - register a UMC device
+ * @umc: pointer to the UMC device
+ *
+ * The memory resource for the UMC device is acquired and the device
+ * registered with the system.
+ */
+int umc_device_register(struct umc_dev *umc)
+{
+       int err;
+
+       err = request_resource(umc->resource.parent, &umc->resource);
+       if (err < 0) {
+               dev_err(&umc->dev, "can't allocate resource range %pR: %d\n",
+                       &umc->resource, err);
+               goto error_request_resource;
+       }
+
+       err = device_register(&umc->dev);
+       if (err < 0)
+               goto error_device_register;
+       return 0;
+
+error_device_register:
+       put_device(&umc->dev);
+       release_resource(&umc->resource);
+error_request_resource:
+       return err;
+}
+EXPORT_SYMBOL_GPL(umc_device_register);
+
+/**
+ * umc_device_unregister - unregister a UMC device
+ * @umc: pointer to the UMC device
+ *
+ * First we unregister the device, make sure the driver can do it's
+ * resource release thing and then we try to release any left over
+ * resources. We take a ref to the device, to make sure it doesn't
+ * disappear under our feet.
+ */
+void umc_device_unregister(struct umc_dev *umc)
+{
+       struct device *dev;
+       if (!umc)
+               return;
+       dev = get_device(&umc->dev);
+       device_unregister(&umc->dev);
+       release_resource(&umc->resource);
+       put_device(dev);
+}
+EXPORT_SYMBOL_GPL(umc_device_unregister);
diff --git a/drivers/staging/uwb/umc-drv.c b/drivers/staging/uwb/umc-drv.c
new file mode 100644 (file)
index 0000000..ed3bd22
--- /dev/null
@@ -0,0 +1,31 @@
+// 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);
diff --git a/drivers/staging/uwb/uwb-debug.c b/drivers/staging/uwb/uwb-debug.c
new file mode 100644 (file)
index 0000000..dd14df2
--- /dev/null
@@ -0,0 +1,354 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Debug support
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * FIXME: doc
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/notifier.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+
+#include "include/debug-cmd.h"
+#include "uwb-internal.h"
+
+/*
+ * Debug interface
+ *
+ * Per radio controller debugfs files (in uwb/uwbN/):
+ *
+ * command: Flexible command interface (see <linux/uwb/debug-cmd.h>).
+ *
+ * reservations: information on reservations.
+ *
+ * accept: Set to true (Y or 1) to accept reservation requests from
+ * peers.
+ *
+ * drp_avail: DRP availability information.
+ */
+
+struct uwb_dbg {
+       struct uwb_pal pal;
+
+       bool accept;
+       struct list_head rsvs;
+
+       struct dentry *root_d;
+       struct dentry *command_f;
+       struct dentry *reservations_f;
+       struct dentry *accept_f;
+       struct dentry *drp_avail_f;
+       spinlock_t list_lock;
+};
+
+static struct dentry *root_dir;
+
+static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv)
+{
+       struct uwb_dbg *dbg = rsv->pal_priv;
+
+       uwb_rsv_dump("debug", rsv);
+
+       if (rsv->state == UWB_RSV_STATE_NONE) {
+               spin_lock(&dbg->list_lock);
+               list_del(&rsv->pal_node);
+               spin_unlock(&dbg->list_lock);
+               uwb_rsv_destroy(rsv);
+       }
+}
+
+static int cmd_rsv_establish(struct uwb_rc *rc,
+                            struct uwb_dbg_cmd_rsv_establish *cmd)
+{
+       struct uwb_mac_addr macaddr;
+       struct uwb_rsv *rsv;
+       struct uwb_dev *target;
+       int ret;
+
+       memcpy(&macaddr, cmd->target, sizeof(macaddr));
+       target = uwb_dev_get_by_macaddr(rc, &macaddr);
+       if (target == NULL)
+               return -ENODEV;
+
+       rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, rc->dbg);
+       if (rsv == NULL) {
+               uwb_dev_put(target);
+               return -ENOMEM;
+       }
+
+       rsv->target.type  = UWB_RSV_TARGET_DEV;
+       rsv->target.dev   = target;
+       rsv->type         = cmd->type;
+       rsv->max_mas      = cmd->max_mas;
+       rsv->min_mas      = cmd->min_mas;
+       rsv->max_interval = cmd->max_interval;
+
+       ret = uwb_rsv_establish(rsv);
+       if (ret)
+               uwb_rsv_destroy(rsv);
+       else {
+               spin_lock(&(rc->dbg)->list_lock);
+               list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
+               spin_unlock(&(rc->dbg)->list_lock);
+       }
+       return ret;
+}
+
+static int cmd_rsv_terminate(struct uwb_rc *rc,
+                            struct uwb_dbg_cmd_rsv_terminate *cmd)
+{
+       struct uwb_rsv *rsv, *found = NULL;
+       int i = 0;
+
+       spin_lock(&(rc->dbg)->list_lock);
+
+       list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) {
+               if (i == cmd->index) {
+                       found = rsv;
+                       uwb_rsv_get(found);
+                       break;
+               }
+               i++;
+       }
+
+       spin_unlock(&(rc->dbg)->list_lock);
+
+       if (!found)
+               return -EINVAL;
+
+       uwb_rsv_terminate(found);
+       uwb_rsv_put(found);
+
+       return 0;
+}
+
+static int cmd_ie_add(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_add)
+{
+       return uwb_rc_ie_add(rc,
+                            (const struct uwb_ie_hdr *) ie_to_add->data,
+                            ie_to_add->len);
+}
+
+static int cmd_ie_rm(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_rm)
+{
+       return uwb_rc_ie_rm(rc, ie_to_rm->data[0]);
+}
+
+static ssize_t command_write(struct file *file, const char __user *buf,
+                        size_t len, loff_t *off)
+{
+       struct uwb_rc *rc = file->private_data;
+       struct uwb_dbg_cmd cmd;
+       int ret = 0;
+       
+       if (len != sizeof(struct uwb_dbg_cmd))
+               return -EINVAL;
+
+       if (copy_from_user(&cmd, buf, len) != 0)
+               return -EFAULT;
+
+       switch (cmd.type) {
+       case UWB_DBG_CMD_RSV_ESTABLISH:
+               ret = cmd_rsv_establish(rc, &cmd.rsv_establish);
+               break;
+       case UWB_DBG_CMD_RSV_TERMINATE:
+               ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate);
+               break;
+       case UWB_DBG_CMD_IE_ADD:
+               ret = cmd_ie_add(rc, &cmd.ie_add);
+               break;
+       case UWB_DBG_CMD_IE_RM:
+               ret = cmd_ie_rm(rc, &cmd.ie_rm);
+               break;
+       case UWB_DBG_CMD_RADIO_START:
+               ret = uwb_radio_start(&rc->dbg->pal);
+               break;
+       case UWB_DBG_CMD_RADIO_STOP:
+               uwb_radio_stop(&rc->dbg->pal);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return ret < 0 ? ret : len;
+}
+
+static const struct file_operations command_fops = {
+       .open   = simple_open,
+       .write  = command_write,
+       .read   = NULL,
+       .llseek = no_llseek,
+       .owner  = THIS_MODULE,
+};
+
+static int reservations_show(struct seq_file *s, void *p)
+{
+       struct uwb_rc *rc = s->private;
+       struct uwb_rsv *rsv;
+
+       mutex_lock(&rc->rsvs_mutex);
+
+       list_for_each_entry(rsv, &rc->reservations, rc_node) {
+               struct uwb_dev_addr devaddr;
+               char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
+               bool is_owner;
+
+               uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
+               if (rsv->target.type == UWB_RSV_TARGET_DEV) {
+                       devaddr = rsv->target.dev->dev_addr;
+                       is_owner = &rc->uwb_dev == rsv->owner;
+               } else {
+                       devaddr = rsv->target.devaddr;
+                       is_owner = true;
+               }
+               uwb_dev_addr_print(target, sizeof(target), &devaddr);
+
+               seq_printf(s, "%c %s -> %s: %s\n",
+                          is_owner ? 'O' : 'T',
+                          owner, target, uwb_rsv_state_str(rsv->state));
+               seq_printf(s, "  stream: %d  type: %s\n",
+                          rsv->stream, uwb_rsv_type_str(rsv->type));
+               seq_printf(s, "  %*pb\n", UWB_NUM_MAS, rsv->mas.bm);
+       }
+
+       mutex_unlock(&rc->rsvs_mutex);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(reservations);
+
+static int drp_avail_show(struct seq_file *s, void *p)
+{
+       struct uwb_rc *rc = s->private;
+
+       seq_printf(s, "global:  %*pb\n", UWB_NUM_MAS, rc->drp_avail.global);
+       seq_printf(s, "local:   %*pb\n", UWB_NUM_MAS, rc->drp_avail.local);
+       seq_printf(s, "pending: %*pb\n", UWB_NUM_MAS, rc->drp_avail.pending);
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(drp_avail);
+
+static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel)
+{
+       struct device *dev = &pal->rc->uwb_dev.dev;
+
+       if (channel > 0)
+               dev_info(dev, "debug: channel %d started\n", channel);
+       else
+               dev_info(dev, "debug: channel stopped\n");
+}
+
+static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv)
+{
+       struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
+
+       if (dbg->accept) {
+               spin_lock(&dbg->list_lock);
+               list_add_tail(&rsv->pal_node, &dbg->rsvs);
+               spin_unlock(&dbg->list_lock);
+               uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, dbg);
+       }
+}
+
+/**
+ * uwb_dbg_add_rc - add a debug interface for a radio controller
+ * @rc: the radio controller
+ */
+void uwb_dbg_add_rc(struct uwb_rc *rc)
+{
+       rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
+       if (rc->dbg == NULL)
+               return;
+
+       INIT_LIST_HEAD(&rc->dbg->rsvs);
+       spin_lock_init(&(rc->dbg)->list_lock);
+
+       uwb_pal_init(&rc->dbg->pal);
+       rc->dbg->pal.rc = rc;
+       rc->dbg->pal.channel_changed = uwb_dbg_channel_changed;
+       rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
+       uwb_pal_register(&rc->dbg->pal);
+
+       if (root_dir) {
+               rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
+                                                    root_dir);
+               rc->dbg->command_f = debugfs_create_file("command", 0200,
+                                                        rc->dbg->root_d, rc,
+                                                        &command_fops);
+               rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
+                                                             rc->dbg->root_d, rc,
+                                                             &reservations_fops);
+               rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
+                                                       rc->dbg->root_d,
+                                                       &rc->dbg->accept);
+               rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
+                                                          rc->dbg->root_d, rc,
+                                                          &drp_avail_fops);
+       }
+}
+
+/**
+ * uwb_dbg_del_rc - remove a radio controller's debug interface
+ * @rc: the radio controller
+ */
+void uwb_dbg_del_rc(struct uwb_rc *rc)
+{
+       struct uwb_rsv *rsv, *t;
+
+       if (rc->dbg == NULL)
+               return;
+
+       list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
+               uwb_rsv_terminate(rsv);
+       }
+
+       uwb_pal_unregister(&rc->dbg->pal);
+
+       if (root_dir) {
+               debugfs_remove(rc->dbg->drp_avail_f);
+               debugfs_remove(rc->dbg->accept_f);
+               debugfs_remove(rc->dbg->reservations_f);
+               debugfs_remove(rc->dbg->command_f);
+               debugfs_remove(rc->dbg->root_d);
+       }
+}
+
+/**
+ * uwb_dbg_exit - initialize the debug interface sub-module
+ */
+void uwb_dbg_init(void)
+{
+       root_dir = debugfs_create_dir("uwb", NULL);
+}
+
+/**
+ * uwb_dbg_exit - clean-up the debug interface sub-module
+ */
+void uwb_dbg_exit(void)
+{
+       debugfs_remove(root_dir);
+}
+
+/**
+ * uwb_dbg_create_pal_dir - create a debugfs directory for a PAL
+ * @pal: The PAL.
+ */
+struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal)
+{
+       struct uwb_rc *rc = pal->rc;
+
+       if (root_dir && rc->dbg && rc->dbg->root_d && pal->name)
+               return debugfs_create_dir(pal->name, rc->dbg->root_d);
+       return NULL;
+}
diff --git a/drivers/staging/uwb/uwb-internal.h b/drivers/staging/uwb/uwb-internal.h
new file mode 100644 (file)
index 0000000..4c2fdac
--- /dev/null
@@ -0,0 +1,366 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Ultra Wide Band
+ * UWB internal API
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This contains most of the internal API for UWB. This is stuff used
+ * across the stack that of course, is of no interest to the rest.
+ *
+ * Some parts might end up going public (like uwb_rc_*())...
+ */
+
+#ifndef __UWB_INTERNAL_H__
+#define __UWB_INTERNAL_H__
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include "uwb.h"
+
+struct uwb_beca_e;
+
+/* General device API */
+extern void uwb_dev_init(struct uwb_dev *uwb_dev);
+extern int __uwb_dev_offair(struct uwb_dev *, struct uwb_rc *);
+extern int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
+                      struct uwb_rc *parent_rc);
+extern void uwb_dev_rm(struct uwb_dev *uwb_dev);
+extern void uwbd_dev_onair(struct uwb_rc *, struct uwb_beca_e *);
+extern void uwbd_dev_offair(struct uwb_beca_e *);
+void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event);
+
+/* General UWB Radio Controller Internal API */
+extern struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *);
+static inline struct uwb_rc *__uwb_rc_get(struct uwb_rc *rc)
+{
+       uwb_dev_get(&rc->uwb_dev);
+       return rc;
+}
+
+static inline void __uwb_rc_put(struct uwb_rc *rc)
+{
+       if (rc)
+               uwb_dev_put(&rc->uwb_dev);
+}
+
+extern int uwb_rc_reset(struct uwb_rc *rc);
+extern int uwb_rc_beacon(struct uwb_rc *rc,
+                        int channel, unsigned bpst_offset);
+extern int uwb_rc_scan(struct uwb_rc *rc,
+                      unsigned channel, enum uwb_scan_type type,
+                      unsigned bpst_offset);
+extern int uwb_rc_send_all_drp_ie(struct uwb_rc *rc);
+
+void uwb_rc_ie_init(struct uwb_rc *);
+int uwb_rc_ie_setup(struct uwb_rc *);
+void uwb_rc_ie_release(struct uwb_rc *);
+int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len,
+                   char *buf, size_t size);
+int uwb_rc_set_ie(struct uwb_rc *, struct uwb_rc_cmd_set_ie *);
+
+
+extern const char *uwb_rc_strerror(unsigned code);
+
+/*
+ * Time to wait for a response to an RC command.
+ *
+ * Some commands can take a long time to response. e.g., START_BEACON
+ * may scan for several superframes before joining an existing beacon
+ * group and this can take around 600 ms.
+ */
+#define UWB_RC_CMD_TIMEOUT_MS 1000 /* ms */
+
+/*
+ * Notification/Event Handlers
+ */
+
+struct uwb_rc_neh;
+
+extern int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
+                           struct uwb_rccb *cmd, size_t cmd_size,
+                           u8 expected_type, u16 expected_event,
+                           uwb_rc_cmd_cb_f cb, void *arg);
+
+
+void uwb_rc_neh_create(struct uwb_rc *rc);
+void uwb_rc_neh_destroy(struct uwb_rc *rc);
+
+struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
+                                 u8 expected_type, u16 expected_event,
+                                 uwb_rc_cmd_cb_f cb, void *arg);
+void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
+void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
+void uwb_rc_neh_put(struct uwb_rc_neh *neh);
+
+/* Event size tables */
+extern int uwb_est_create(void);
+extern void uwb_est_destroy(void);
+
+/*
+ * UWB conflicting alien reservations
+ */
+struct uwb_cnflt_alien {
+       struct uwb_rc *rc;
+       struct list_head rc_node;
+       struct uwb_mas_bm mas;
+       struct timer_list timer;
+       struct work_struct cnflt_update_work;
+};
+
+enum uwb_uwb_rsv_alloc_result {
+       UWB_RSV_ALLOC_FOUND = 0,
+       UWB_RSV_ALLOC_NOT_FOUND,
+};
+
+enum uwb_rsv_mas_status {
+       UWB_RSV_MAS_NOT_AVAIL = 1,
+       UWB_RSV_MAS_SAFE,
+       UWB_RSV_MAS_UNSAFE,
+};
+
+struct uwb_rsv_col_set_info {
+       unsigned char start_col;
+       unsigned char interval;
+       unsigned char safe_mas_per_col;
+       unsigned char unsafe_mas_per_col;
+};
+
+struct uwb_rsv_col_info {
+       unsigned char max_avail_safe;
+       unsigned char max_avail_unsafe;
+       unsigned char highest_mas[UWB_MAS_PER_ZONE];
+       struct uwb_rsv_col_set_info csi;
+};
+
+struct uwb_rsv_row_info {
+       unsigned char avail[UWB_MAS_PER_ZONE];
+       unsigned char free_rows;
+       unsigned char used_rows;
+};
+
+/*
+ * UWB find allocation
+ */
+struct uwb_rsv_alloc_info {
+       unsigned char bm[UWB_MAS_PER_ZONE * UWB_NUM_ZONES];
+       struct uwb_rsv_col_info ci[UWB_NUM_ZONES];
+       struct uwb_rsv_row_info ri;
+       struct uwb_mas_bm *not_available;
+       struct uwb_mas_bm *result;
+       int min_mas;
+       int max_mas;
+       int max_interval;
+       int total_allocated_mases;
+       int safe_allocated_mases;
+       int unsafe_allocated_mases;
+       int interval;
+};
+
+int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv,
+                                struct uwb_mas_bm *available,
+                                struct uwb_mas_bm *result);
+void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc);
+/*
+ * UWB Events & management daemon
+ */
+
+/**
+ * enum uwb_event_type - types of UWB management daemon events
+ *
+ * The UWB management daemon (uwbd) can receive two types of events:
+ *   UWB_EVT_TYPE_NOTIF - notification from the radio controller.
+ *   UWB_EVT_TYPE_MSG   - a simple message.
+ */
+enum uwb_event_type {
+       UWB_EVT_TYPE_NOTIF,
+       UWB_EVT_TYPE_MSG,
+};
+
+/**
+ * struct uwb_event_notif - an event for a radio controller notification
+ * @size: Size of the buffer (ie: Guaranteed to contain at least
+ *        a full 'struct uwb_rceb')
+ * @rceb: Pointer to a kmalloced() event payload
+ */
+struct uwb_event_notif {
+       size_t size;
+       struct uwb_rceb *rceb;
+};
+
+/**
+ * enum uwb_event_message - an event for a message for asynchronous processing
+ *
+ * UWB_EVT_MSG_RESET - reset the radio controller and all PAL hardware.
+ */
+enum uwb_event_message {
+       UWB_EVT_MSG_RESET,
+};
+
+/**
+ * UWB Event
+ * @rc:         Radio controller that emitted the event (referenced)
+ * @ts_jiffies: Timestamp, when was it received
+ * @type:       This event's type.
+ */
+struct uwb_event {
+       struct list_head list_node;
+       struct uwb_rc *rc;
+       unsigned long ts_jiffies;
+       enum uwb_event_type type;
+       union {
+               struct uwb_event_notif notif;
+               enum uwb_event_message message;
+       };
+};
+
+extern void uwbd_start(struct uwb_rc *rc);
+extern void uwbd_stop(struct uwb_rc *rc);
+extern struct uwb_event *uwb_event_alloc(size_t, gfp_t gfp_mask);
+extern void uwbd_event_queue(struct uwb_event *);
+void uwbd_flush(struct uwb_rc *rc);
+
+/* UWB event handlers */
+extern int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *);
+extern int uwbd_evt_handle_rc_beacon(struct uwb_event *);
+extern int uwbd_evt_handle_rc_beacon_size(struct uwb_event *);
+extern int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *);
+extern int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *);
+extern int uwbd_evt_handle_rc_drp(struct uwb_event *);
+extern int uwbd_evt_handle_rc_drp_avail(struct uwb_event *);
+
+int uwbd_msg_handle_reset(struct uwb_event *evt);
+
+
+/*
+ * Address management
+ */
+int uwb_rc_dev_addr_assign(struct uwb_rc *rc);
+int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt);
+
+/*
+ * UWB Beacon Cache
+ *
+ * Each beacon we received is kept in a cache--when we receive that
+ * beacon consistently, that means there is a new device that we have
+ * to add to the system.
+ */
+
+extern unsigned long beacon_timeout_ms;
+
+/**
+ * Beacon cache entry
+ *
+ * @jiffies_refresh: last time a beacon was  received that refreshed
+ *                   this cache entry.
+ * @uwb_dev: device connected to this beacon. This pointer is not
+ *           safe, you need to get it with uwb_dev_try_get()
+ *
+ * @hits: how many time we have seen this beacon since last time we
+ *        cleared it
+ */
+struct uwb_beca_e {
+       struct mutex mutex;
+       struct kref refcnt;
+       struct list_head node;
+       struct uwb_mac_addr *mac_addr;
+       struct uwb_dev_addr dev_addr;
+       u8 hits;
+       unsigned long ts_jiffies;
+       struct uwb_dev *uwb_dev;
+       struct uwb_rc_evt_beacon *be;
+       struct stats lqe_stats, rssi_stats;     /* radio statistics */
+};
+struct uwb_beacon_frame;
+extern ssize_t uwb_bce_print_IEs(struct uwb_dev *, struct uwb_beca_e *,
+                                char *, size_t);
+
+extern void uwb_bce_kfree(struct kref *_bce);
+static inline void uwb_bce_get(struct uwb_beca_e *bce)
+{
+       kref_get(&bce->refcnt);
+}
+static inline void uwb_bce_put(struct uwb_beca_e *bce)
+{
+       kref_put(&bce->refcnt, uwb_bce_kfree);
+}
+extern void uwb_beca_purge(struct uwb_rc *rc);
+extern void uwb_beca_release(struct uwb_rc *rc);
+
+struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
+                                      const struct uwb_dev_addr *devaddr);
+struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
+                                      const struct uwb_mac_addr *macaddr);
+
+int uwb_radio_setup(struct uwb_rc *rc);
+void uwb_radio_reset_state(struct uwb_rc *rc);
+void uwb_radio_shutdown(struct uwb_rc *rc);
+int uwb_radio_force_channel(struct uwb_rc *rc, int channel);
+
+/* -- UWB Sysfs representation */
+extern struct class uwb_rc_class;
+extern struct bus_type uwb_bus_type;
+extern struct device_attribute dev_attr_mac_address;
+extern struct device_attribute dev_attr_beacon;
+extern struct device_attribute dev_attr_scan;
+
+/* -- DRP Bandwidth allocator: bandwidth allocations, reservations, DRP */
+void uwb_rsv_init(struct uwb_rc *rc);
+int uwb_rsv_setup(struct uwb_rc *rc);
+void uwb_rsv_cleanup(struct uwb_rc *rc);
+void uwb_rsv_remove_all(struct uwb_rc *rc);
+void uwb_rsv_get(struct uwb_rsv *rsv);
+void uwb_rsv_put(struct uwb_rsv *rsv);
+bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv);
+void uwb_rsv_dump(char *text, struct uwb_rsv *rsv);
+int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available);
+void uwb_rsv_backoff_win_timer(struct timer_list *t);
+void uwb_rsv_backoff_win_increment(struct uwb_rc *rc);
+int uwb_rsv_status(struct uwb_rsv *rsv);
+int uwb_rsv_companion_status(struct uwb_rsv *rsv);
+
+void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state);
+void uwb_rsv_remove(struct uwb_rsv *rsv);
+struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
+                            struct uwb_ie_drp *drp_ie);
+void uwb_rsv_sched_update(struct uwb_rc *rc);
+void uwb_rsv_queue_update(struct uwb_rc *rc);
+
+int uwb_drp_ie_update(struct uwb_rsv *rsv);
+void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie);
+
+void uwb_drp_avail_init(struct uwb_rc *rc);
+void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail);
+int  uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas);
+void uwb_drp_avail_ie_update(struct uwb_rc *rc);
+
+/* -- PAL support */
+void uwb_rc_pal_init(struct uwb_rc *rc);
+
+/* -- Misc */
+
+extern ssize_t uwb_mac_frame_hdr_print(char *, size_t,
+                                      const struct uwb_mac_frame_hdr *);
+
+/* -- Debug interface */
+void uwb_dbg_init(void);
+void uwb_dbg_exit(void);
+void uwb_dbg_add_rc(struct uwb_rc *rc);
+void uwb_dbg_del_rc(struct uwb_rc *rc);
+struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal);
+
+static inline void uwb_dev_lock(struct uwb_dev *uwb_dev)
+{
+       device_lock(&uwb_dev->dev);
+}
+
+static inline void uwb_dev_unlock(struct uwb_dev *uwb_dev)
+{
+       device_unlock(&uwb_dev->dev);
+}
+
+#endif /* #ifndef __UWB_INTERNAL_H__ */
diff --git a/drivers/staging/uwb/uwb.h b/drivers/staging/uwb/uwb.h
new file mode 100644 (file)
index 0000000..6a59706
--- /dev/null
@@ -0,0 +1,817 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Ultra Wide Band
+ * UWB API
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: doc: overview of the API, different parts and pointers
+ */
+
+#ifndef __LINUX__UWB_H__
+#define __LINUX__UWB_H__
+
+#include <linux/limits.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <asm/page.h>
+#include "include/spec.h"
+
+struct uwb_dev;
+struct uwb_beca_e;
+struct uwb_rc;
+struct uwb_rsv;
+struct uwb_dbg;
+
+/**
+ * struct uwb_dev - a UWB Device
+ * @rc: UWB Radio Controller that discovered the device (kind of its
+ *     parent).
+ * @bce: a beacon cache entry for this device; or NULL if the device
+ *     is a local radio controller.
+ * @mac_addr: the EUI-48 address of this device.
+ * @dev_addr: the current DevAddr used by this device.
+ * @beacon_slot: the slot number the beacon is using.
+ * @streams: bitmap of streams allocated to reservations targeted at
+ *     this device.  For an RC, this is the streams allocated for
+ *     reservations targeted at DevAddrs.
+ *
+ * A UWB device may either by a neighbor or part of a local radio
+ * controller.
+ */
+struct uwb_dev {
+       struct mutex mutex;
+       struct list_head list_node;
+       struct device dev;
+       struct uwb_rc *rc;              /* radio controller */
+       struct uwb_beca_e *bce;         /* Beacon Cache Entry */
+
+       struct uwb_mac_addr mac_addr;
+       struct uwb_dev_addr dev_addr;
+       int beacon_slot;
+       DECLARE_BITMAP(streams, UWB_NUM_STREAMS);
+       DECLARE_BITMAP(last_availability_bm, UWB_NUM_MAS);
+};
+#define to_uwb_dev(d) container_of(d, struct uwb_dev, dev)
+
+/**
+ * UWB HWA/WHCI Radio Control {Command|Event} Block context IDs
+ *
+ * RC[CE]Bs have a 'context ID' field that matches the command with
+ * the event received to confirm it.
+ *
+ * Maximum number of context IDs
+ */
+enum { UWB_RC_CTX_MAX = 256 };
+
+
+/** Notification chain head for UWB generated events to listeners */
+struct uwb_notifs_chain {
+       struct list_head list;
+       struct mutex mutex;
+};
+
+/* Beacon cache list */
+struct uwb_beca {
+       struct list_head list;
+       size_t entries;
+       struct mutex mutex;
+};
+
+/* Event handling thread. */
+struct uwbd {
+       int pid;
+       struct task_struct *task;
+       wait_queue_head_t wq;
+       struct list_head event_list;
+       spinlock_t event_list_lock;
+};
+
+/**
+ * struct uwb_mas_bm - a bitmap of all MAS in a superframe
+ * @bm: a bitmap of length #UWB_NUM_MAS
+ */
+struct uwb_mas_bm {
+       DECLARE_BITMAP(bm, UWB_NUM_MAS);
+       DECLARE_BITMAP(unsafe_bm, UWB_NUM_MAS);
+       int safe;
+       int unsafe;
+};
+
+/**
+ * uwb_rsv_state - UWB Reservation state.
+ *
+ * NONE - reservation is not active (no DRP IE being transmitted).
+ *
+ * Owner reservation states:
+ *
+ * INITIATED - owner has sent an initial DRP request.
+ * PENDING - target responded with pending Reason Code.
+ * MODIFIED - reservation manager is modifying an established
+ * reservation with a different MAS allocation.
+ * ESTABLISHED - the reservation has been successfully negotiated.
+ *
+ * Target reservation states:
+ *
+ * DENIED - request is denied.
+ * ACCEPTED - request is accepted.
+ * PENDING - PAL has yet to make a decision to whether to accept or
+ * deny.
+ *
+ * FIXME: further target states TBD.
+ */
+enum uwb_rsv_state {
+       UWB_RSV_STATE_NONE = 0,
+       UWB_RSV_STATE_O_INITIATED,
+       UWB_RSV_STATE_O_PENDING,
+       UWB_RSV_STATE_O_MODIFIED,
+       UWB_RSV_STATE_O_ESTABLISHED,
+       UWB_RSV_STATE_O_TO_BE_MOVED,
+       UWB_RSV_STATE_O_MOVE_EXPANDING,
+       UWB_RSV_STATE_O_MOVE_COMBINING,
+       UWB_RSV_STATE_O_MOVE_REDUCING,
+       UWB_RSV_STATE_T_ACCEPTED,
+       UWB_RSV_STATE_T_DENIED,
+       UWB_RSV_STATE_T_CONFLICT,
+       UWB_RSV_STATE_T_PENDING,
+       UWB_RSV_STATE_T_EXPANDING_ACCEPTED,
+       UWB_RSV_STATE_T_EXPANDING_CONFLICT,
+       UWB_RSV_STATE_T_EXPANDING_PENDING,
+       UWB_RSV_STATE_T_EXPANDING_DENIED,
+       UWB_RSV_STATE_T_RESIZED,
+
+       UWB_RSV_STATE_LAST,
+};
+
+enum uwb_rsv_target_type {
+       UWB_RSV_TARGET_DEV,
+       UWB_RSV_TARGET_DEVADDR,
+};
+
+/**
+ * struct uwb_rsv_target - the target of a reservation.
+ *
+ * Reservations unicast and targeted at a single device
+ * (UWB_RSV_TARGET_DEV); or (e.g., in the case of WUSB) targeted at a
+ * specific (private) DevAddr (UWB_RSV_TARGET_DEVADDR).
+ */
+struct uwb_rsv_target {
+       enum uwb_rsv_target_type type;
+       union {
+               struct uwb_dev *dev;
+               struct uwb_dev_addr devaddr;
+       };
+};
+
+struct uwb_rsv_move {
+       struct uwb_mas_bm final_mas;
+       struct uwb_ie_drp *companion_drp_ie;
+       struct uwb_mas_bm companion_mas;
+};
+
+/*
+ * Number of streams reserved for reservations targeted at DevAddrs.
+ */
+#define UWB_NUM_GLOBAL_STREAMS 1
+
+typedef void (*uwb_rsv_cb_f)(struct uwb_rsv *rsv);
+
+/**
+ * struct uwb_rsv - a DRP reservation
+ *
+ * Data structure management:
+ *
+ * @rc:             the radio controller this reservation is for
+ *                  (as target or owner)
+ * @rc_node:        a list node for the RC
+ * @pal_node:       a list node for the PAL
+ *
+ * Owner and target parameters:
+ *
+ * @owner:          the UWB device owning this reservation
+ * @target:         the target UWB device
+ * @type:           reservation type
+ *
+ * Owner parameters:
+ *
+ * @max_mas:        maxiumum number of MAS
+ * @min_mas:        minimum number of MAS
+ * @sparsity:       owner selected sparsity
+ * @is_multicast:   true iff multicast
+ *
+ * @callback:       callback function when the reservation completes
+ * @pal_priv:       private data for the PAL making the reservation
+ *
+ * Reservation status:
+ *
+ * @status:         negotiation status
+ * @stream:         stream index allocated for this reservation
+ * @tiebreaker:     conflict tiebreaker for this reservation
+ * @mas:            reserved MAS
+ * @drp_ie:         the DRP IE
+ * @ie_valid:       true iff the DRP IE matches the reservation parameters
+ *
+ * DRP reservations are uniquely identified by the owner, target and
+ * stream index.  However, when using a DevAddr as a target (e.g., for
+ * a WUSB cluster reservation) the responses may be received from
+ * devices with different DevAddrs.  In this case, reservations are
+ * uniquely identified by just the stream index.  A number of stream
+ * indexes (UWB_NUM_GLOBAL_STREAMS) are reserved for this.
+ */
+struct uwb_rsv {
+       struct uwb_rc *rc;
+       struct list_head rc_node;
+       struct list_head pal_node;
+       struct kref kref;
+
+       struct uwb_dev *owner;
+       struct uwb_rsv_target target;
+       enum uwb_drp_type type;
+       int max_mas;
+       int min_mas;
+       int max_interval;
+       bool is_multicast;
+
+       uwb_rsv_cb_f callback;
+       void *pal_priv;
+
+       enum uwb_rsv_state state;
+       bool needs_release_companion_mas;
+       u8 stream;
+       u8 tiebreaker;
+       struct uwb_mas_bm mas;
+       struct uwb_ie_drp *drp_ie;
+       struct uwb_rsv_move mv;
+       bool ie_valid;
+       struct timer_list timer;
+       struct work_struct handle_timeout_work;
+};
+
+static const
+struct uwb_mas_bm uwb_mas_bm_zero = { .bm = { 0 } };
+
+static inline void uwb_mas_bm_copy_le(void *dst, const struct uwb_mas_bm *mas)
+{
+       bitmap_copy_le(dst, mas->bm, UWB_NUM_MAS);
+}
+
+/**
+ * struct uwb_drp_avail - a radio controller's view of MAS usage
+ * @global:   MAS unused by neighbors (excluding reservations targeted
+ *            or owned by the local radio controller) or the beaon period
+ * @local:    MAS unused by local established reservations
+ * @pending:  MAS unused by local pending reservations
+ * @ie:       DRP Availability IE to be included in the beacon
+ * @ie_valid: true iff @ie is valid and does not need to regenerated from
+ *            @global and @local
+ *
+ * Each radio controller maintains a view of MAS usage or
+ * availability. MAS available for a new reservation are determined
+ * from the intersection of @global, @local, and @pending.
+ *
+ * The radio controller must transmit a DRP Availability IE that's the
+ * intersection of @global and @local.
+ *
+ * A set bit indicates the MAS is unused and available.
+ *
+ * rc->rsvs_mutex should be held before accessing this data structure.
+ *
+ * [ECMA-368] section 17.4.3.
+ */
+struct uwb_drp_avail {
+       DECLARE_BITMAP(global, UWB_NUM_MAS);
+       DECLARE_BITMAP(local, UWB_NUM_MAS);
+       DECLARE_BITMAP(pending, UWB_NUM_MAS);
+       struct uwb_ie_drp_avail ie;
+       bool ie_valid;
+};
+
+struct uwb_drp_backoff_win {
+       u8 window;
+       u8 n;
+       int total_expired;
+       struct timer_list timer;
+       bool can_reserve_extra_mases;
+};
+
+const char *uwb_rsv_state_str(enum uwb_rsv_state state);
+const char *uwb_rsv_type_str(enum uwb_drp_type type);
+
+struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb,
+                              void *pal_priv);
+void uwb_rsv_destroy(struct uwb_rsv *rsv);
+
+int uwb_rsv_establish(struct uwb_rsv *rsv);
+int uwb_rsv_modify(struct uwb_rsv *rsv,
+                  int max_mas, int min_mas, int sparsity);
+void uwb_rsv_terminate(struct uwb_rsv *rsv);
+
+void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv);
+
+void uwb_rsv_get_usable_mas(struct uwb_rsv *orig_rsv, struct uwb_mas_bm *mas);
+
+/**
+ * Radio Control Interface instance
+ *
+ *
+ * Life cycle rules: those of the UWB Device.
+ *
+ * @index:    an index number for this radio controller, as used in the
+ *            device name.
+ * @version:  version of protocol supported by this device
+ * @priv:     Backend implementation; rw with uwb_dev.dev.sem taken.
+ * @cmd:      Backend implementation to execute commands; rw and call
+ *            only  with uwb_dev.dev.sem taken.
+ * @reset:    Hardware reset of radio controller and any PAL controllers.
+ * @filter:   Backend implementation to manipulate data to and from device
+ *            to be compliant to specification assumed by driver (WHCI
+ *            0.95).
+ *
+ *            uwb_dev.dev.mutex is used to execute commands and update
+ *            the corresponding structures; can't use a spinlock
+ *            because rc->cmd() can sleep.
+ * @ies:         This is a dynamically allocated array cacheing the
+ *               IEs (settable by the host) that the beacon of this
+ *               radio controller is currently sending.
+ *
+ *               In reality, we store here the full command we set to
+ *               the radio controller (which is basically a command
+ *               prefix followed by all the IEs the beacon currently
+ *               contains). This way we don't have to realloc and
+ *               memcpy when setting it.
+ *
+ *               We set this up in uwb_rc_ie_setup(), where we alloc
+ *               this struct, call get_ie() [so we know which IEs are
+ *               currently being sent, if any].
+ *
+ * @ies_capacity:Amount of space (in bytes) allocated in @ies. The
+ *               amount used is given by sizeof(*ies) plus ies->wIELength
+ *               (which is a little endian quantity all the time).
+ * @ies_mutex:   protect the IE cache
+ * @dbg:         information for the debug interface
+ */
+struct uwb_rc {
+       struct uwb_dev uwb_dev;
+       int index;
+       u16 version;
+
+       struct module *owner;
+       void *priv;
+       int (*start)(struct uwb_rc *rc);
+       void (*stop)(struct uwb_rc *rc);
+       int (*cmd)(struct uwb_rc *, const struct uwb_rccb *, size_t);
+       int (*reset)(struct uwb_rc *rc);
+       int (*filter_cmd)(struct uwb_rc *, struct uwb_rccb **, size_t *);
+       int (*filter_event)(struct uwb_rc *, struct uwb_rceb **, const size_t,
+                           size_t *, size_t *);
+
+       spinlock_t neh_lock;            /* protects neh_* and ctx_* */
+       struct list_head neh_list;      /* Open NE handles */
+       unsigned long ctx_bm[UWB_RC_CTX_MAX / 8 / sizeof(unsigned long)];
+       u8 ctx_roll;
+
+       int beaconing;                  /* Beaconing state [channel number] */
+       int beaconing_forced;
+       int scanning;
+       enum uwb_scan_type scan_type:3;
+       unsigned ready:1;
+       struct uwb_notifs_chain notifs_chain;
+       struct uwb_beca uwb_beca;
+
+       struct uwbd uwbd;
+
+       struct uwb_drp_backoff_win bow;
+       struct uwb_drp_avail drp_avail;
+       struct list_head reservations;
+       struct list_head cnflt_alien_list;
+       struct uwb_mas_bm cnflt_alien_bitmap;
+       struct mutex rsvs_mutex;
+       spinlock_t rsvs_lock;
+       struct workqueue_struct *rsv_workq;
+
+       struct delayed_work rsv_update_work;
+       struct delayed_work rsv_alien_bp_work;
+       int set_drp_ie_pending;
+       struct mutex ies_mutex;
+       struct uwb_rc_cmd_set_ie *ies;
+       size_t ies_capacity;
+
+       struct list_head pals;
+       int active_pals;
+
+       struct uwb_dbg *dbg;
+};
+
+
+/**
+ * struct uwb_pal - a UWB PAL
+ * @name:    descriptive name for this PAL (wusbhc, wlp, etc.).
+ * @device:  a device for the PAL.  Used to link the PAL and the radio
+ *           controller in sysfs.
+ * @rc:      the radio controller the PAL uses.
+ * @channel_changed: called when the channel used by the radio changes.
+ *           A channel of -1 means the channel has been stopped.
+ * @new_rsv: called when a peer requests a reservation (may be NULL if
+ *           the PAL cannot accept reservation requests).
+ * @channel: channel being used by the PAL; 0 if the PAL isn't using
+ *           the radio; -1 if the PAL wishes to use the radio but
+ *           cannot.
+ * @debugfs_dir: a debugfs directory which the PAL can use for its own
+ *           debugfs files.
+ *
+ * A Protocol Adaptation Layer (PAL) is a user of the WiMedia UWB
+ * radio platform (e.g., WUSB, WLP or Bluetooth UWB AMP).
+ *
+ * The PALs using a radio controller must register themselves to
+ * permit the UWB stack to coordinate usage of the radio between the
+ * various PALs or to allow PALs to response to certain requests from
+ * peers.
+ *
+ * A struct uwb_pal should be embedded in a containing structure
+ * belonging to the PAL and initialized with uwb_pal_init()).  Fields
+ * should be set appropriately by the PAL before registering the PAL
+ * with uwb_pal_register().
+ */
+struct uwb_pal {
+       struct list_head node;
+       const char *name;
+       struct device *device;
+       struct uwb_rc *rc;
+
+       void (*channel_changed)(struct uwb_pal *pal, int channel);
+       void (*new_rsv)(struct uwb_pal *pal, struct uwb_rsv *rsv);
+
+       int channel;
+       struct dentry *debugfs_dir;
+};
+
+void uwb_pal_init(struct uwb_pal *pal);
+int uwb_pal_register(struct uwb_pal *pal);
+void uwb_pal_unregister(struct uwb_pal *pal);
+
+int uwb_radio_start(struct uwb_pal *pal);
+void uwb_radio_stop(struct uwb_pal *pal);
+
+/*
+ * General public API
+ *
+ * This API can be used by UWB device drivers or by those implementing
+ * UWB Radio Controllers
+ */
+struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
+                                      const struct uwb_dev_addr *devaddr);
+struct uwb_dev *uwb_dev_get_by_rc(struct uwb_dev *, struct uwb_rc *);
+static inline void uwb_dev_get(struct uwb_dev *uwb_dev)
+{
+       get_device(&uwb_dev->dev);
+}
+static inline void uwb_dev_put(struct uwb_dev *uwb_dev)
+{
+       put_device(&uwb_dev->dev);
+}
+struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev);
+
+/**
+ * Callback function for 'uwb_{dev,rc}_foreach()'.
+ *
+ * @dev:  Linux device instance
+ *        'uwb_dev = container_of(dev, struct uwb_dev, dev)'
+ * @priv: Data passed by the caller to 'uwb_{dev,rc}_foreach()'.
+ *
+ * @returns: 0 to continue the iterations, any other val to stop
+ *           iterating and return the value to the caller of
+ *           _foreach().
+ */
+typedef int (*uwb_dev_for_each_f)(struct device *dev, void *priv);
+int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f func, void *priv);
+
+struct uwb_rc *uwb_rc_alloc(void);
+struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *);
+struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *);
+void uwb_rc_put(struct uwb_rc *rc);
+
+typedef void (*uwb_rc_cmd_cb_f)(struct uwb_rc *rc, void *arg,
+                                struct uwb_rceb *reply, ssize_t reply_size);
+
+int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
+                    struct uwb_rccb *cmd, size_t cmd_size,
+                    u8 expected_type, u16 expected_event,
+                    uwb_rc_cmd_cb_f cb, void *arg);
+ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
+                  struct uwb_rccb *cmd, size_t cmd_size,
+                  struct uwb_rceb *reply, size_t reply_size);
+ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name,
+                   struct uwb_rccb *cmd, size_t cmd_size,
+                   u8 expected_type, u16 expected_event,
+                   struct uwb_rceb **preply);
+
+size_t __uwb_addr_print(char *, size_t, const unsigned char *, int);
+
+int uwb_rc_dev_addr_set(struct uwb_rc *, const struct uwb_dev_addr *);
+int uwb_rc_dev_addr_get(struct uwb_rc *, struct uwb_dev_addr *);
+int uwb_rc_mac_addr_set(struct uwb_rc *, const struct uwb_mac_addr *);
+int uwb_rc_mac_addr_get(struct uwb_rc *, struct uwb_mac_addr *);
+int __uwb_mac_addr_assigned_check(struct device *, void *);
+int __uwb_dev_addr_assigned_check(struct device *, void *);
+
+/* Print in @buf a pretty repr of @addr */
+static inline size_t uwb_dev_addr_print(char *buf, size_t buf_size,
+                                       const struct uwb_dev_addr *addr)
+{
+       return __uwb_addr_print(buf, buf_size, addr->data, 0);
+}
+
+/* Print in @buf a pretty repr of @addr */
+static inline size_t uwb_mac_addr_print(char *buf, size_t buf_size,
+                                       const struct uwb_mac_addr *addr)
+{
+       return __uwb_addr_print(buf, buf_size, addr->data, 1);
+}
+
+/* @returns 0 if device addresses @addr2 and @addr1 are equal */
+static inline int uwb_dev_addr_cmp(const struct uwb_dev_addr *addr1,
+                                  const struct uwb_dev_addr *addr2)
+{
+       return memcmp(addr1, addr2, sizeof(*addr1));
+}
+
+/* @returns 0 if MAC addresses @addr2 and @addr1 are equal */
+static inline int uwb_mac_addr_cmp(const struct uwb_mac_addr *addr1,
+                                  const struct uwb_mac_addr *addr2)
+{
+       return memcmp(addr1, addr2, sizeof(*addr1));
+}
+
+/* @returns !0 if a MAC @addr is a broadcast address */
+static inline int uwb_mac_addr_bcast(const struct uwb_mac_addr *addr)
+{
+       struct uwb_mac_addr bcast = {
+               .data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+       };
+       return !uwb_mac_addr_cmp(addr, &bcast);
+}
+
+/* @returns !0 if a MAC @addr is all zeroes*/
+static inline int uwb_mac_addr_unset(const struct uwb_mac_addr *addr)
+{
+       struct uwb_mac_addr unset = {
+               .data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+       };
+       return !uwb_mac_addr_cmp(addr, &unset);
+}
+
+/* @returns !0 if the address is in use. */
+static inline unsigned __uwb_dev_addr_assigned(struct uwb_rc *rc,
+                                              struct uwb_dev_addr *addr)
+{
+       return uwb_dev_for_each(rc, __uwb_dev_addr_assigned_check, addr);
+}
+
+/*
+ * UWB Radio Controller API
+ *
+ * This API is used (in addition to the general API) to implement UWB
+ * Radio Controllers.
+ */
+void uwb_rc_init(struct uwb_rc *);
+int uwb_rc_add(struct uwb_rc *, struct device *dev, void *rc_priv);
+void uwb_rc_rm(struct uwb_rc *);
+void uwb_rc_neh_grok(struct uwb_rc *, void *, size_t);
+void uwb_rc_neh_error(struct uwb_rc *, int);
+void uwb_rc_reset_all(struct uwb_rc *rc);
+void uwb_rc_pre_reset(struct uwb_rc *rc);
+int uwb_rc_post_reset(struct uwb_rc *rc);
+
+/**
+ * uwb_rsv_is_owner - is the owner of this reservation the RC?
+ * @rsv: the reservation
+ */
+static inline bool uwb_rsv_is_owner(struct uwb_rsv *rsv)
+{
+       return rsv->owner == &rsv->rc->uwb_dev;
+}
+
+/**
+ * enum uwb_notifs - UWB events that can be passed to any listeners
+ * @UWB_NOTIF_ONAIR: a new neighbour has joined the beacon group.
+ * @UWB_NOTIF_OFFAIR: a neighbour has left the beacon group.
+ *
+ * Higher layers can register callback functions with the radio
+ * controller using uwb_notifs_register(). The radio controller
+ * maintains a list of all registered handlers and will notify all
+ * nodes when an event occurs.
+ */
+enum uwb_notifs {
+       UWB_NOTIF_ONAIR,
+       UWB_NOTIF_OFFAIR,
+};
+
+/* Callback function registered with UWB */
+struct uwb_notifs_handler {
+       struct list_head list_node;
+       void (*cb)(void *, struct uwb_dev *, enum uwb_notifs);
+       void *data;
+};
+
+int uwb_notifs_register(struct uwb_rc *, struct uwb_notifs_handler *);
+int uwb_notifs_deregister(struct uwb_rc *, struct uwb_notifs_handler *);
+
+
+/**
+ * UWB radio controller Event Size Entry (for creating entry tables)
+ *
+ * WUSB and WHCI define events and notifications, and they might have
+ * fixed or variable size.
+ *
+ * Each event/notification has a size which is not necessarily known
+ * in advance based on the event code. As well, vendor specific
+ * events/notifications will have a size impossible to determine
+ * unless we know about the device's specific details.
+ *
+ * It was way too smart of the spec writers not to think that it would
+ * be impossible for a generic driver to skip over vendor specific
+ * events/notifications if there are no LENGTH fields in the HEADER of
+ * each message...the transaction size cannot be counted on as the
+ * spec does not forbid to pack more than one event in a single
+ * transaction.
+ *
+ * Thus, we guess sizes with tables (or for events, when you know the
+ * size ahead of time you can use uwb_rc_neh_extra_size*()). We
+ * register tables with the known events and their sizes, and then we
+ * traverse those tables. For those with variable length, we provide a
+ * way to lookup the size inside the event/notification's
+ * payload. This allows device-specific event size tables to be
+ * registered.
+ *
+ * @size:   Size of the payload
+ *
+ * @offset: if != 0, at offset @offset-1 starts a field with a length
+ *          that has to be added to @size. The format of the field is
+ *          given by @type.
+ *
+ * @type:   Type and length of the offset field. Most common is LE 16
+ *          bits (that's why that is zero); others are there mostly to
+ *          cover for bugs and weirdos.
+ */
+struct uwb_est_entry {
+       size_t size;
+       unsigned offset;
+       enum { UWB_EST_16 = 0, UWB_EST_8 = 1 } type;
+};
+
+int uwb_est_register(u8 type, u8 code_high, u16 vendor, u16 product,
+                    const struct uwb_est_entry *, size_t entries);
+int uwb_est_unregister(u8 type, u8 code_high, u16 vendor, u16 product,
+                      const struct uwb_est_entry *, size_t entries);
+ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
+                         size_t len);
+
+/* -- Misc */
+
+enum {
+       EDC_MAX_ERRORS = 10,
+       EDC_ERROR_TIMEFRAME = HZ,
+};
+
+/* error density counter */
+struct edc {
+       unsigned long timestart;
+       u16 errorcount;
+};
+
+static inline
+void edc_init(struct edc *edc)
+{
+       edc->timestart = jiffies;
+}
+
+/* Called when an error occurred.
+ * This is way to determine if the number of acceptable errors per time
+ * period has been exceeded. It is not accurate as there are cases in which
+ * this scheme will not work, for example if there are periodic occurrences
+ * of errors that straddle updates to the start time. This scheme is
+ * sufficient for our usage.
+ *
+ * @returns 1 if maximum acceptable errors per timeframe has been exceeded.
+ */
+static inline int edc_inc(struct edc *err_hist, u16 max_err, u16 timeframe)
+{
+       unsigned long now;
+
+       now = jiffies;
+       if (now - err_hist->timestart > timeframe) {
+               err_hist->errorcount = 1;
+               err_hist->timestart = now;
+       } else if (++err_hist->errorcount > max_err) {
+                       err_hist->errorcount = 0;
+                       err_hist->timestart = now;
+                       return 1;
+       }
+       return 0;
+}
+
+
+/* Information Element handling */
+
+struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len);
+int uwb_rc_ie_add(struct uwb_rc *uwb_rc, const struct uwb_ie_hdr *ies, size_t size);
+int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id);
+
+/*
+ * Transmission statistics
+ *
+ * UWB uses LQI and RSSI (one byte values) for reporting radio signal
+ * strength and line quality indication. We do quick and dirty
+ * averages of those. They are signed values, btw.
+ *
+ * For 8 bit quantities, we keep the min, the max, an accumulator
+ * (@sigma) and a # of samples. When @samples gets to 255, we compute
+ * the average (@sigma / @samples), place it in @sigma and reset
+ * @samples to 1 (so we use it as the first sample).
+ *
+ * Now, statistically speaking, probably I am kicking the kidneys of
+ * some books I have in my shelves collecting dust, but I just want to
+ * get an approx, not the Nobel.
+ *
+ * LOCKING: there is no locking per se, but we try to keep a lockless
+ * schema. Only _add_samples() modifies the values--as long as you
+ * have other locking on top that makes sure that no two calls of
+ * _add_sample() happen at the same time, then we are fine. Now, for
+ * resetting the values we just set @samples to 0 and that makes the
+ * next _add_sample() to start with defaults. Reading the values in
+ * _show() currently can race, so you need to make sure the calls are
+ * under the same lock that protects calls to _add_sample(). FIXME:
+ * currently unlocked (It is not ultraprecise but does the trick. Bite
+ * me).
+ */
+struct stats {
+       s8 min, max;
+       s16 sigma;
+       atomic_t samples;
+};
+
+static inline
+void stats_init(struct stats *stats)
+{
+       atomic_set(&stats->samples, 0);
+       wmb();
+}
+
+static inline
+void stats_add_sample(struct stats *stats, s8 sample)
+{
+       s8 min, max;
+       s16 sigma;
+       unsigned samples = atomic_read(&stats->samples);
+       if (samples == 0) {     /* it was zero before, so we initialize */
+               min = 127;
+               max = -128;
+               sigma = 0;
+       } else {
+               min = stats->min;
+               max = stats->max;
+               sigma = stats->sigma;
+       }
+
+       if (sample < min)       /* compute new values */
+               min = sample;
+       else if (sample > max)
+               max = sample;
+       sigma += sample;
+
+       stats->min = min;       /* commit */
+       stats->max = max;
+       stats->sigma = sigma;
+       if (atomic_add_return(1, &stats->samples) > 255) {
+               /* wrapped around! reset */
+               stats->sigma = sigma / 256;
+               atomic_set(&stats->samples, 1);
+       }
+}
+
+static inline ssize_t stats_show(struct stats *stats, char *buf)
+{
+       int min, max, avg;
+       int samples = atomic_read(&stats->samples);
+       if (samples == 0)
+               min = max = avg = 0;
+       else {
+               min = stats->min;
+               max = stats->max;
+               avg = stats->sigma / samples;
+       }
+       return scnprintf(buf, PAGE_SIZE, "%d %d %d\n", min, max, avg);
+}
+
+static inline ssize_t stats_store(struct stats *stats, const char *buf,
+                                 size_t size)
+{
+       stats_init(stats);
+       return size;
+}
+
+#endif /* #ifndef __LINUX__UWB_H__ */
diff --git a/drivers/staging/uwb/uwbd.c b/drivers/staging/uwb/uwbd.c
new file mode 100644 (file)
index 0000000..dc5c743
--- /dev/null
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Ultra Wide Band
+ * Neighborhood Management Daemon
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This daemon takes care of maintaing information that describes the
+ * UWB neighborhood that the radios in this machine can see. It also
+ * keeps a tab of which devices are visible, makes sure each HC sits
+ * on a different channel to avoid interfering, etc.
+ *
+ * Different drivers (radio controller, device, any API in general)
+ * communicate with this daemon through an event queue. Daemon wakes
+ * up, takes a list of events and handles them one by one; handling
+ * function is extracted from a table based on the event's type and
+ * subtype. Events are freed only if the handling function says so.
+ *
+ *   . Lock protecting the event list has to be an spinlock and locked
+ *     with IRQSAVE because it might be called from an interrupt
+ *     context (ie: when events arrive and the notification drops
+ *     down from the ISR).
+ *
+ *   . UWB radio controller drivers queue events to the daemon using
+ *     uwbd_event_queue(). They just get the event, chew it to make it
+ *     look like UWBD likes it and pass it in a buffer allocated with
+ *     uwb_event_alloc().
+ *
+ * EVENTS
+ *
+ * Events have a type, a subtype, a length, some other stuff and the
+ * data blob, which depends on the event. The header is 'struct
+ * uwb_event'; for payloads, see 'struct uwbd_evt_*'.
+ *
+ * EVENT HANDLER TABLES
+ *
+ * To find a handling function for an event, the type is used to index
+ * a subtype-table in the type-table. The subtype-table is indexed
+ * with the subtype to get the function that handles the event. Start
+ * with the main type-table 'uwbd_evt_type_handler'.
+ *
+ * DEVICES
+ *
+ * Devices are created when a bunch of beacons have been received and
+ * it is stablished that the device has stable radio presence. CREATED
+ * only, not configured. Devices are ONLY configured when an
+ * Application-Specific IE Probe is receieved, in which the device
+ * declares which Protocol ID it groks. Then the device is CONFIGURED
+ * (and the driver->probe() stuff of the device model is invoked).
+ *
+ * Devices are considered disconnected when a certain number of
+ * beacons are not received in an amount of time.
+ *
+ * Handler functions are called normally uwbd_evt_handle_*().
+ */
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/freezer.h>
+
+#include "uwb-internal.h"
+
+/*
+ * UWBD Event handler function signature
+ *
+ * Return !0 if the event needs not to be freed (ie the handler
+ * takes/took care of it). 0 means the daemon code will free the
+ * event.
+ *
+ * @evt->rc is already referenced and guaranteed to exist. See
+ * uwb_evt_handle().
+ */
+typedef int (*uwbd_evt_handler_f)(struct uwb_event *);
+
+/**
+ * Properties of a UWBD event
+ *
+ * @handler:    the function that will handle this event
+ * @name:       text name of event
+ */
+struct uwbd_event {
+       uwbd_evt_handler_f handler;
+       const char *name;
+};
+
+/* Table of handlers for and properties of the UWBD Radio Control Events */
+static struct uwbd_event uwbd_urc_events[] = {
+       [UWB_RC_EVT_IE_RCV] = {
+               .handler = uwbd_evt_handle_rc_ie_rcv,
+               .name = "IE_RECEIVED"
+       },
+       [UWB_RC_EVT_BEACON] = {
+               .handler = uwbd_evt_handle_rc_beacon,
+               .name = "BEACON_RECEIVED"
+       },
+       [UWB_RC_EVT_BEACON_SIZE] = {
+               .handler = uwbd_evt_handle_rc_beacon_size,
+               .name = "BEACON_SIZE_CHANGE"
+       },
+       [UWB_RC_EVT_BPOIE_CHANGE] = {
+               .handler = uwbd_evt_handle_rc_bpoie_change,
+               .name = "BPOIE_CHANGE"
+       },
+       [UWB_RC_EVT_BP_SLOT_CHANGE] = {
+               .handler = uwbd_evt_handle_rc_bp_slot_change,
+               .name = "BP_SLOT_CHANGE"
+       },
+       [UWB_RC_EVT_DRP_AVAIL] = {
+               .handler = uwbd_evt_handle_rc_drp_avail,
+               .name = "DRP_AVAILABILITY_CHANGE"
+       },
+       [UWB_RC_EVT_DRP] = {
+               .handler = uwbd_evt_handle_rc_drp,
+               .name = "DRP"
+       },
+       [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
+               .handler = uwbd_evt_handle_rc_dev_addr_conflict,
+               .name = "DEV_ADDR_CONFLICT",
+       },
+};
+
+
+
+struct uwbd_evt_type_handler {
+       const char *name;
+       struct uwbd_event *uwbd_events;
+       size_t size;
+};
+
+/* Table of handlers for each UWBD Event type. */
+static struct uwbd_evt_type_handler uwbd_urc_evt_type_handlers[] = {
+       [UWB_RC_CET_GENERAL] = {
+               .name        = "URC",
+               .uwbd_events = uwbd_urc_events,
+               .size        = ARRAY_SIZE(uwbd_urc_events),
+       },
+};
+
+static const struct uwbd_event uwbd_message_handlers[] = {
+       [UWB_EVT_MSG_RESET] = {
+               .handler = uwbd_msg_handle_reset,
+               .name = "reset",
+       },
+};
+
+/*
+ * Handle an URC event passed to the UWB Daemon
+ *
+ * @evt: the event to handle
+ * @returns: 0 if the event can be kfreed, !0 on the contrary
+ *           (somebody else took ownership) [coincidentally, returning
+ *           a <0 errno code will free it :)].
+ *
+ * Looks up the two indirection tables (one for the type, one for the
+ * subtype) to decide which function handles it and then calls the
+ * handler.
+ *
+ * The event structure passed to the event handler has the radio
+ * controller in @evt->rc referenced. The reference will be dropped
+ * once the handler returns, so if it needs it for longer (async),
+ * it'll need to take another one.
+ */
+static
+int uwbd_event_handle_urc(struct uwb_event *evt)
+{
+       int result = -EINVAL;
+       struct uwbd_evt_type_handler *type_table;
+       uwbd_evt_handler_f handler;
+       u8 type, context;
+       u16 event;
+
+       type = evt->notif.rceb->bEventType;
+       event = le16_to_cpu(evt->notif.rceb->wEvent);
+       context = evt->notif.rceb->bEventContext;
+
+       if (type >= ARRAY_SIZE(uwbd_urc_evt_type_handlers))
+               goto out;
+       type_table = &uwbd_urc_evt_type_handlers[type];
+       if (type_table->uwbd_events == NULL)
+               goto out;
+       if (event >= type_table->size)
+               goto out;
+       handler = type_table->uwbd_events[event].handler;
+       if (handler == NULL)
+               goto out;
+
+       result = (*handler)(evt);
+out:
+       if (result < 0)
+               dev_err(&evt->rc->uwb_dev.dev,
+                       "UWBD: event 0x%02x/%04x/%02x, handling failed: %d\n",
+                       type, event, context, result);
+       return result;
+}
+
+static void uwbd_event_handle_message(struct uwb_event *evt)
+{
+       struct uwb_rc *rc;
+       int result;
+
+       rc = evt->rc;
+
+       if (evt->message < 0 || evt->message >= ARRAY_SIZE(uwbd_message_handlers)) {
+               dev_err(&rc->uwb_dev.dev, "UWBD: invalid message type %d\n", evt->message);
+               return;
+       }
+
+       result = uwbd_message_handlers[evt->message].handler(evt);
+       if (result < 0)
+               dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n",
+                       uwbd_message_handlers[evt->message].name, result);
+}
+
+static void uwbd_event_handle(struct uwb_event *evt)
+{
+       struct uwb_rc *rc;
+       int should_keep;
+
+       rc = evt->rc;
+
+       if (rc->ready) {
+               switch (evt->type) {
+               case UWB_EVT_TYPE_NOTIF:
+                       should_keep = uwbd_event_handle_urc(evt);
+                       if (should_keep <= 0)
+                               kfree(evt->notif.rceb);
+                       break;
+               case UWB_EVT_TYPE_MSG:
+                       uwbd_event_handle_message(evt);
+                       break;
+               default:
+                       dev_err(&rc->uwb_dev.dev, "UWBD: invalid event type %d\n", evt->type);
+                       break;
+               }
+       }
+
+       __uwb_rc_put(rc);       /* for the __uwb_rc_get() in uwb_rc_notif_cb() */
+}
+
+/**
+ * UWB Daemon
+ *
+ * Listens to all UWB notifications and takes care to track the state
+ * of the UWB neighbourhood for the kernel. When we do a run, we
+ * spinlock, move the list to a private copy and release the
+ * lock. Hold it as little as possible. Not a conflict: it is
+ * guaranteed we own the events in the private list.
+ *
+ * FIXME: should change so we don't have a 1HZ timer all the time, but
+ *        only if there are devices.
+ */
+static int uwbd(void *param)
+{
+       struct uwb_rc *rc = param;
+       unsigned long flags;
+       struct uwb_event *evt;
+       int should_stop = 0;
+
+       while (1) {
+               wait_event_interruptible_timeout(
+                       rc->uwbd.wq,
+                       !list_empty(&rc->uwbd.event_list)
+                         || (should_stop = kthread_should_stop()),
+                       HZ);
+               if (should_stop)
+                       break;
+
+               spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
+               if (!list_empty(&rc->uwbd.event_list)) {
+                       evt = list_first_entry(&rc->uwbd.event_list, struct uwb_event, list_node);
+                       list_del(&evt->list_node);
+               } else
+                       evt = NULL;
+               spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
+
+               if (evt) {
+                       uwbd_event_handle(evt);
+                       kfree(evt);
+               }
+
+               uwb_beca_purge(rc);     /* Purge devices that left */
+       }
+       return 0;
+}
+
+
+/** Start the UWB daemon */
+void uwbd_start(struct uwb_rc *rc)
+{
+       struct task_struct *task = kthread_run(uwbd, rc, "uwbd");
+       if (IS_ERR(task)) {
+               rc->uwbd.task = NULL;
+               printk(KERN_ERR "UWB: Cannot start management daemon; "
+                      "UWB won't work\n");
+       } else {
+               rc->uwbd.task = task;
+               rc->uwbd.pid = rc->uwbd.task->pid;
+       }
+}
+
+/* Stop the UWB daemon and free any unprocessed events */
+void uwbd_stop(struct uwb_rc *rc)
+{
+       if (rc->uwbd.task)
+               kthread_stop(rc->uwbd.task);
+       uwbd_flush(rc);
+}
+
+/*
+ * Queue an event for the management daemon
+ *
+ * When some lower layer receives an event, it uses this function to
+ * push it forward to the UWB daemon.
+ *
+ * Once you pass the event, you don't own it any more, but the daemon
+ * does. It will uwb_event_free() it when done, so make sure you
+ * uwb_event_alloc()ed it or bad things will happen.
+ *
+ * If the daemon is not running, we just free the event.
+ */
+void uwbd_event_queue(struct uwb_event *evt)
+{
+       struct uwb_rc *rc = evt->rc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
+       if (rc->uwbd.pid != 0) {
+               list_add(&evt->list_node, &rc->uwbd.event_list);
+               wake_up_all(&rc->uwbd.wq);
+       } else {
+               __uwb_rc_put(evt->rc);
+               if (evt->type == UWB_EVT_TYPE_NOTIF)
+                       kfree(evt->notif.rceb);
+               kfree(evt);
+       }
+       spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
+       return;
+}
+
+void uwbd_flush(struct uwb_rc *rc)
+{
+       struct uwb_event *evt, *nxt;
+
+       spin_lock_irq(&rc->uwbd.event_list_lock);
+       list_for_each_entry_safe(evt, nxt, &rc->uwbd.event_list, list_node) {
+               if (evt->rc == rc) {
+                       __uwb_rc_put(rc);
+                       list_del(&evt->list_node);
+                       if (evt->type == UWB_EVT_TYPE_NOTIF)
+                               kfree(evt->notif.rceb);
+                       kfree(evt);
+               }
+       }
+       spin_unlock_irq(&rc->uwbd.event_list_lock);
+}
diff --git a/drivers/staging/uwb/whc-rc.c b/drivers/staging/uwb/whc-rc.c
new file mode 100644 (file)
index 0000000..34020ed
--- /dev/null
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Wireless Host Controller: Radio Control Interface (WHCI v0.95[2.3])
+ * Radio Control command/event transport to the UWB stack
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Initialize and hook up the Radio Control interface.
+ *
+ * For each device probed, creates an 'struct whcrc' which contains
+ * just the representation of the UWB Radio Controller, and the logic
+ * for reading notifications and passing them to the UWB Core.
+ *
+ * So we initialize all of those, register the UWB Radio Controller
+ * and setup the notification/event handle to pipe the notifications
+ * to the UWB management Daemon.
+ *
+ * Once uwb_rc_add() is called, the UWB stack takes control, resets
+ * the radio and readies the device to take commands the UWB
+ * API/user-space.
+ *
+ * Note this driver is just a transport driver; the commands are
+ * formed at the UWB stack and given to this driver who will deliver
+ * them to the hw and transfer the replies/notifications back to the
+ * UWB stack through the UWB daemon (UWBD).
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include "uwb.h"
+#include "include/whci.h"
+#include "include/umc.h"
+
+#include "uwb-internal.h"
+
+/**
+ * Descriptor for an instance of the UWB Radio Control Driver that
+ * attaches to the URC interface of the WHCI PCI card.
+ *
+ * Unless there is a lock specific to the 'data members', all access
+ * is protected by uwb_rc->mutex.
+ */
+struct whcrc {
+       struct umc_dev *umc_dev;
+       struct uwb_rc *uwb_rc;          /* UWB host controller */
+
+       unsigned long area;
+       void __iomem *rc_base;
+       size_t rc_len;
+       spinlock_t irq_lock;
+
+       void *evt_buf, *cmd_buf;
+       dma_addr_t evt_dma_buf, cmd_dma_buf;
+       wait_queue_head_t cmd_wq;
+       struct work_struct event_work;
+};
+
+/**
+ * Execute an UWB RC command on WHCI/RC
+ *
+ * @rc:       Instance of a Radio Controller that is a whcrc
+ * @cmd:      Buffer containing the RCCB and payload to execute
+ * @cmd_size: Size of the command buffer.
+ *
+ * We copy the command into whcrc->cmd_buf (as it is pretty and
+ * aligned`and physically contiguous) and then press the right keys in
+ * the controller's URCCMD register to get it to read it. We might
+ * have to wait for the cmd_sem to be open to us.
+ *
+ * NOTE: rc's mutex has to be locked
+ */
+static int whcrc_cmd(struct uwb_rc *uwb_rc,
+             const struct uwb_rccb *cmd, size_t cmd_size)
+{
+       int result = 0;
+       struct whcrc *whcrc = uwb_rc->priv;
+       struct device *dev = &whcrc->umc_dev->dev;
+       u32 urccmd;
+
+       if (cmd_size >= 4096)
+               return -EINVAL;
+
+       /*
+        * If the URC is halted, then the hardware has reset itself.
+        * Attempt to recover by restarting the device and then return
+        * an error as it's likely that the current command isn't
+        * valid for a newly started RC.
+        */
+       if (le_readl(whcrc->rc_base + URCSTS) & URCSTS_HALTED) {
+               dev_err(dev, "requesting reset of halted radio controller\n");
+               uwb_rc_reset_all(uwb_rc);
+               return -EIO;
+       }
+
+       result = wait_event_timeout(whcrc->cmd_wq,
+               !(le_readl(whcrc->rc_base + URCCMD) & URCCMD_ACTIVE), HZ/2);
+       if (result == 0) {
+               dev_err(dev, "device is not ready to execute commands\n");
+               return -ETIMEDOUT;
+       }
+
+       memmove(whcrc->cmd_buf, cmd, cmd_size);
+       le_writeq(whcrc->cmd_dma_buf, whcrc->rc_base + URCCMDADDR);
+
+       spin_lock(&whcrc->irq_lock);
+       urccmd = le_readl(whcrc->rc_base + URCCMD);
+       urccmd &= ~(URCCMD_EARV | URCCMD_SIZE_MASK);
+       le_writel(urccmd | URCCMD_ACTIVE | URCCMD_IWR | cmd_size,
+                 whcrc->rc_base + URCCMD);
+       spin_unlock(&whcrc->irq_lock);
+
+       return 0;
+}
+
+static int whcrc_reset(struct uwb_rc *rc)
+{
+       struct whcrc *whcrc = rc->priv;
+
+       return umc_controller_reset(whcrc->umc_dev);
+}
+
+/**
+ * Reset event reception mechanism and tell hw we are ready to get more
+ *
+ * We have read all the events in the event buffer, so we are ready to
+ * reset it to the beginning.
+ *
+ * This is only called during initialization or after an event buffer
+ * has been retired.  This means we can be sure that event processing
+ * is disabled and it's safe to update the URCEVTADDR register.
+ *
+ * There's no need to wait for the event processing to start as the
+ * URC will not clear URCCMD_ACTIVE until (internal) event buffer
+ * space is available.
+ */
+static
+void whcrc_enable_events(struct whcrc *whcrc)
+{
+       u32 urccmd;
+
+       le_writeq(whcrc->evt_dma_buf, whcrc->rc_base + URCEVTADDR);
+
+       spin_lock(&whcrc->irq_lock);
+       urccmd = le_readl(whcrc->rc_base + URCCMD) & ~URCCMD_ACTIVE;
+       le_writel(urccmd | URCCMD_EARV, whcrc->rc_base + URCCMD);
+       spin_unlock(&whcrc->irq_lock);
+}
+
+static void whcrc_event_work(struct work_struct *work)
+{
+       struct whcrc *whcrc = container_of(work, struct whcrc, event_work);
+       size_t size;
+       u64 urcevtaddr;
+
+       urcevtaddr = le_readq(whcrc->rc_base + URCEVTADDR);
+       size = urcevtaddr & URCEVTADDR_OFFSET_MASK;
+
+       uwb_rc_neh_grok(whcrc->uwb_rc, whcrc->evt_buf, size);
+       whcrc_enable_events(whcrc);
+}
+
+/**
+ * Catch interrupts?
+ *
+ * We ack inmediately (and expect the hw to do the right thing and
+ * raise another IRQ if things have changed :)
+ */
+static
+irqreturn_t whcrc_irq_cb(int irq, void *_whcrc)
+{
+       struct whcrc *whcrc = _whcrc;
+       struct device *dev = &whcrc->umc_dev->dev;
+       u32 urcsts;
+
+       urcsts = le_readl(whcrc->rc_base + URCSTS);
+       if (!(urcsts & URCSTS_INT_MASK))
+               return IRQ_NONE;
+       le_writel(urcsts & URCSTS_INT_MASK, whcrc->rc_base + URCSTS);
+
+       if (urcsts & URCSTS_HSE) {
+               dev_err(dev, "host system error -- hardware halted\n");
+               /* FIXME: do something sensible here */
+               goto out;
+       }
+       if (urcsts & URCSTS_ER)
+               schedule_work(&whcrc->event_work);
+       if (urcsts & URCSTS_RCI)
+               wake_up_all(&whcrc->cmd_wq);
+out:
+       return IRQ_HANDLED;
+}
+
+
+/**
+ * Initialize a UMC RC interface: map regions, get (shared) IRQ
+ */
+static
+int whcrc_setup_rc_umc(struct whcrc *whcrc)
+{
+       int result = 0;
+       struct device *dev = &whcrc->umc_dev->dev;
+       struct umc_dev *umc_dev = whcrc->umc_dev;
+
+       whcrc->area = umc_dev->resource.start;
+       whcrc->rc_len = resource_size(&umc_dev->resource);
+       result = -EBUSY;
+       if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME) == NULL) {
+               dev_err(dev, "can't request URC region (%zu bytes @ 0x%lx): %d\n",
+                       whcrc->rc_len, whcrc->area, result);
+               goto error_request_region;
+       }
+
+       whcrc->rc_base = ioremap_nocache(whcrc->area, whcrc->rc_len);
+       if (whcrc->rc_base == NULL) {
+               dev_err(dev, "can't ioremap registers (%zu bytes @ 0x%lx): %d\n",
+                       whcrc->rc_len, whcrc->area, result);
+               goto error_ioremap_nocache;
+       }
+
+       result = request_irq(umc_dev->irq, whcrc_irq_cb, IRQF_SHARED,
+                            KBUILD_MODNAME, whcrc);
+       if (result < 0) {
+               dev_err(dev, "can't allocate IRQ %d: %d\n",
+                       umc_dev->irq, result);
+               goto error_request_irq;
+       }
+
+       result = -ENOMEM;
+       whcrc->cmd_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
+                                           &whcrc->cmd_dma_buf, GFP_KERNEL);
+       if (whcrc->cmd_buf == NULL) {
+               dev_err(dev, "Can't allocate cmd transfer buffer\n");
+               goto error_cmd_buffer;
+       }
+
+       whcrc->evt_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
+                                           &whcrc->evt_dma_buf, GFP_KERNEL);
+       if (whcrc->evt_buf == NULL) {
+               dev_err(dev, "Can't allocate evt transfer buffer\n");
+               goto error_evt_buffer;
+       }
+       return 0;
+
+error_evt_buffer:
+       dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
+                         whcrc->cmd_dma_buf);
+error_cmd_buffer:
+       free_irq(umc_dev->irq, whcrc);
+error_request_irq:
+       iounmap(whcrc->rc_base);
+error_ioremap_nocache:
+       release_mem_region(whcrc->area, whcrc->rc_len);
+error_request_region:
+       return result;
+}
+
+
+/**
+ * Release RC's UMC resources
+ */
+static
+void whcrc_release_rc_umc(struct whcrc *whcrc)
+{
+       struct umc_dev *umc_dev = whcrc->umc_dev;
+
+       dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->evt_buf,
+                         whcrc->evt_dma_buf);
+       dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
+                         whcrc->cmd_dma_buf);
+       free_irq(umc_dev->irq, whcrc);
+       iounmap(whcrc->rc_base);
+       release_mem_region(whcrc->area, whcrc->rc_len);
+}
+
+
+/**
+ * whcrc_start_rc - start a WHCI radio controller
+ * @whcrc: the radio controller to start
+ *
+ * Reset the UMC device, start the radio controller, enable events and
+ * finally enable interrupts.
+ */
+static int whcrc_start_rc(struct uwb_rc *rc)
+{
+       struct whcrc *whcrc = rc->priv;
+       struct device *dev = &whcrc->umc_dev->dev;
+
+       /* Reset the thing */
+       le_writel(URCCMD_RESET, whcrc->rc_base + URCCMD);
+       if (whci_wait_for(dev, whcrc->rc_base + URCCMD, URCCMD_RESET, 0,
+                         5000, "hardware reset") < 0)
+               return -EBUSY;
+
+       /* Set the event buffer, start the controller (enable IRQs later) */
+       le_writel(0, whcrc->rc_base + URCINTR);
+       le_writel(URCCMD_RS, whcrc->rc_base + URCCMD);
+       if (whci_wait_for(dev, whcrc->rc_base + URCSTS, URCSTS_HALTED, 0,
+                         5000, "radio controller start") < 0)
+               return -ETIMEDOUT;
+       whcrc_enable_events(whcrc);
+       le_writel(URCINTR_EN_ALL, whcrc->rc_base + URCINTR);
+       return 0;
+}
+
+
+/**
+ * whcrc_stop_rc - stop a WHCI radio controller
+ * @whcrc: the radio controller to stop
+ *
+ * Disable interrupts and cancel any pending event processing work
+ * before clearing the Run/Stop bit.
+ */
+static
+void whcrc_stop_rc(struct uwb_rc *rc)
+{
+       struct whcrc *whcrc = rc->priv;
+       struct umc_dev *umc_dev = whcrc->umc_dev;
+
+       le_writel(0, whcrc->rc_base + URCINTR);
+       cancel_work_sync(&whcrc->event_work);
+
+       le_writel(0, whcrc->rc_base + URCCMD);
+       whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS,
+                     URCSTS_HALTED, URCSTS_HALTED, 100, "radio controller stop");
+}
+
+static void whcrc_init(struct whcrc *whcrc)
+{
+       spin_lock_init(&whcrc->irq_lock);
+       init_waitqueue_head(&whcrc->cmd_wq);
+       INIT_WORK(&whcrc->event_work, whcrc_event_work);
+}
+
+/**
+ * Initialize the radio controller.
+ *
+ * NOTE: we setup whcrc->uwb_rc before calling uwb_rc_add(); in the
+ *       IRQ handler we use that to determine if the hw is ready to
+ *       handle events. Looks like a race condition, but it really is
+ *       not.
+ */
+static
+int whcrc_probe(struct umc_dev *umc_dev)
+{
+       int result;
+       struct uwb_rc *uwb_rc;
+       struct whcrc *whcrc;
+       struct device *dev = &umc_dev->dev;
+
+       result = -ENOMEM;
+       uwb_rc = uwb_rc_alloc();
+       if (uwb_rc == NULL) {
+               dev_err(dev, "unable to allocate RC instance\n");
+               goto error_rc_alloc;
+       }
+       whcrc = kzalloc(sizeof(*whcrc), GFP_KERNEL);
+       if (whcrc == NULL) {
+               dev_err(dev, "unable to allocate WHC-RC instance\n");
+               goto error_alloc;
+       }
+       whcrc_init(whcrc);
+       whcrc->umc_dev = umc_dev;
+
+       result = whcrc_setup_rc_umc(whcrc);
+       if (result < 0) {
+               dev_err(dev, "Can't setup RC UMC interface: %d\n", result);
+               goto error_setup_rc_umc;
+       }
+       whcrc->uwb_rc = uwb_rc;
+
+       uwb_rc->owner = THIS_MODULE;
+       uwb_rc->cmd   = whcrc_cmd;
+       uwb_rc->reset = whcrc_reset;
+       uwb_rc->start = whcrc_start_rc;
+       uwb_rc->stop  = whcrc_stop_rc;
+
+       result = uwb_rc_add(uwb_rc, dev, whcrc);
+       if (result < 0)
+               goto error_rc_add;
+       umc_set_drvdata(umc_dev, whcrc);
+       return 0;
+
+error_rc_add:
+       whcrc_release_rc_umc(whcrc);
+error_setup_rc_umc:
+       kfree(whcrc);
+error_alloc:
+       uwb_rc_put(uwb_rc);
+error_rc_alloc:
+       return result;
+}
+
+/**
+ * Clean up the radio control resources
+ *
+ * When we up the command semaphore, everybody possibly held trying to
+ * execute a command should be granted entry and then they'll see the
+ * host is quiescing and up it (so it will chain to the next waiter).
+ * This should not happen (in any case), as we can only remove when
+ * there are no handles open...
+ */
+static void whcrc_remove(struct umc_dev *umc_dev)
+{
+       struct whcrc *whcrc = umc_get_drvdata(umc_dev);
+       struct uwb_rc *uwb_rc = whcrc->uwb_rc;
+
+       umc_set_drvdata(umc_dev, NULL);
+       uwb_rc_rm(uwb_rc);
+       whcrc_release_rc_umc(whcrc);
+       kfree(whcrc);
+       uwb_rc_put(uwb_rc);
+}
+
+static int whcrc_pre_reset(struct umc_dev *umc)
+{
+       struct whcrc *whcrc = umc_get_drvdata(umc);
+       struct uwb_rc *uwb_rc = whcrc->uwb_rc;
+
+       uwb_rc_pre_reset(uwb_rc);
+       return 0;
+}
+
+static int whcrc_post_reset(struct umc_dev *umc)
+{
+       struct whcrc *whcrc = umc_get_drvdata(umc);
+       struct uwb_rc *uwb_rc = whcrc->uwb_rc;
+
+       return uwb_rc_post_reset(uwb_rc);
+}
+
+/* PCI device ID's that we handle [so it gets loaded] */
+static struct pci_device_id __used whcrc_id_table[] = {
+       { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
+       { /* empty last entry */ }
+};
+MODULE_DEVICE_TABLE(pci, whcrc_id_table);
+
+static struct umc_driver whcrc_driver = {
+       .name       = "whc-rc",
+       .cap_id     = UMC_CAP_ID_WHCI_RC,
+       .probe      = whcrc_probe,
+       .remove     = whcrc_remove,
+       .pre_reset  = whcrc_pre_reset,
+       .post_reset = whcrc_post_reset,
+};
+
+static int __init whcrc_driver_init(void)
+{
+       return umc_driver_register(&whcrc_driver);
+}
+module_init(whcrc_driver_init);
+
+static void __exit whcrc_driver_exit(void)
+{
+       umc_driver_unregister(&whcrc_driver);
+}
+module_exit(whcrc_driver_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless Host Controller Radio Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/uwb/whci.c b/drivers/staging/uwb/whci.c
new file mode 100644 (file)
index 0000000..a8832f6
--- /dev/null
@@ -0,0 +1,257 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * WHCI UWB Multi-interface Controller enumerator.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include "include/whci.h"
+#include "include/umc.h"
+
+struct whci_card {
+       struct pci_dev *pci;
+       void __iomem *uwbbase;
+       u8 n_caps;
+       struct umc_dev *devs[0];
+};
+
+
+/* Fix faulty HW :( */
+static
+u64 whci_capdata_quirks(struct whci_card *card, u64 capdata)
+{
+       u64 capdata_orig = capdata;
+       struct pci_dev *pci_dev = card->pci;
+       if (pci_dev->vendor == PCI_VENDOR_ID_INTEL
+           && (pci_dev->device == 0x0c3b || pci_dev->device == 0004)
+           && pci_dev->class == 0x0d1010) {
+               switch (UWBCAPDATA_TO_CAP_ID(capdata)) {
+                       /* WLP capability has 0x100 bytes of aperture */
+               case 0x80:
+                       capdata |= 0x40 << 8; break;
+                       /* WUSB capability has 0x80 bytes of aperture
+                        * and ID is 1 */
+               case 0x02:
+                       capdata &= ~0xffff;
+                       capdata |= 0x2001;
+                       break;
+               }
+       }
+       if (capdata_orig != capdata)
+               dev_warn(&pci_dev->dev,
+                        "PCI v%04x d%04x c%06x#%02x: "
+                        "corrected capdata from %016Lx to %016Lx\n",
+                        pci_dev->vendor, pci_dev->device, pci_dev->class,
+                        (unsigned)UWBCAPDATA_TO_CAP_ID(capdata),
+                        (unsigned long long)capdata_orig,
+                        (unsigned long long)capdata);
+       return capdata;
+}
+
+
+/**
+ * whci_wait_for - wait for a WHCI register to be set
+ *
+ * Polls (for at most @max_ms ms) until '*@reg & @mask == @result'.
+ */
+int whci_wait_for(struct device *dev, u32 __iomem *reg, u32 mask, u32 result,
+       unsigned long max_ms, const char *tag)
+{
+       unsigned t = 0;
+       u32 val;
+       for (;;) {
+               val = le_readl(reg);
+               if ((val & mask) == result)
+                       break;
+               if (t >= max_ms) {
+                       dev_err(dev, "%s timed out\n", tag);
+                       return -ETIMEDOUT;
+               }
+               msleep(10);
+               t += 10;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(whci_wait_for);
+
+
+/*
+ * NOTE: the capinfo and capdata registers are slightly different
+ *       (size and cap-id fields). So for cap #0, we need to fill
+ *       in. Size comes from the size of the register block
+ *       (statically calculated); cap_id comes from nowhere, we use
+ *       zero, that is reserved, for the radio controller, because
+ *       none was defined at the spec level.
+ */
+static int whci_add_cap(struct whci_card *card, int n)
+{
+       struct umc_dev *umc;
+       u64 capdata;
+       int bar, err;
+
+       umc = umc_device_create(&card->pci->dev, n);
+       if (umc == NULL)
+               return -ENOMEM;
+
+       capdata = le_readq(card->uwbbase + UWBCAPDATA(n));
+
+       bar = UWBCAPDATA_TO_BAR(capdata) << 1;
+
+       capdata = whci_capdata_quirks(card, capdata);
+       /* Capability 0 is the radio controller. It's size is 32
+        * bytes (WHCI0.95[2.3, T2-9]). */
+       umc->version         = UWBCAPDATA_TO_VERSION(capdata);
+       umc->cap_id          = n == 0 ? 0 : UWBCAPDATA_TO_CAP_ID(capdata);
+       umc->bar             = bar;
+       umc->resource.start  = pci_resource_start(card->pci, bar)
+               + UWBCAPDATA_TO_OFFSET(capdata);
+       umc->resource.end    = umc->resource.start
+               + (n == 0 ? 0x20 : UWBCAPDATA_TO_SIZE(capdata)) - 1;
+       umc->resource.name   = dev_name(&umc->dev);
+       umc->resource.flags  = card->pci->resource[bar].flags;
+       umc->resource.parent = &card->pci->resource[bar];
+       umc->irq             = card->pci->irq;
+
+       err = umc_device_register(umc);
+       if (err < 0)
+               goto error;
+       card->devs[n] = umc;
+       return 0;
+
+error:
+       kfree(umc);
+       return err;
+}
+
+static void whci_del_cap(struct whci_card *card, int n)
+{
+       struct umc_dev *umc = card->devs[n];
+
+       umc_device_unregister(umc);
+}
+
+static int whci_n_caps(struct pci_dev *pci)
+{
+       void __iomem *uwbbase;
+       u64 capinfo;
+
+       uwbbase = pci_iomap(pci, 0, 8);
+       if (!uwbbase)
+               return -ENOMEM;
+       capinfo = le_readq(uwbbase + UWBCAPINFO);
+       pci_iounmap(pci, uwbbase);
+
+       return UWBCAPINFO_TO_N_CAPS(capinfo);
+}
+
+static int whci_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+       struct whci_card *card;
+       int err, n_caps, n;
+
+       err = pci_enable_device(pci);
+       if (err < 0)
+               goto error;
+       pci_enable_msi(pci);
+       pci_set_master(pci);
+       err = -ENXIO;
+       if (!pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
+               pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
+       else if (!pci_set_dma_mask(pci, DMA_BIT_MASK(32)))
+               pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
+       else
+               goto error_dma;
+
+       err = n_caps = whci_n_caps(pci);
+       if (n_caps < 0)
+               goto error_ncaps;
+
+       err = -ENOMEM;
+       card = kzalloc(sizeof(struct whci_card)
+                      + sizeof(struct umc_dev *) * (n_caps + 1),
+                      GFP_KERNEL);
+       if (card == NULL)
+               goto error_kzalloc;
+       card->pci = pci;
+       card->n_caps = n_caps;
+
+       err = -EBUSY;
+       if (!request_mem_region(pci_resource_start(pci, 0),
+                               UWBCAPDATA_SIZE(card->n_caps),
+                               "whci (capability data)"))
+               goto error_request_memregion;
+       err = -ENOMEM;
+       card->uwbbase = pci_iomap(pci, 0, UWBCAPDATA_SIZE(card->n_caps));
+       if (!card->uwbbase)
+               goto error_iomap;
+
+       /* Add each capability. */
+       for (n = 0; n <= card->n_caps; n++) {
+               err = whci_add_cap(card, n);
+               if (err < 0 && n == 0) {
+                       dev_err(&pci->dev, "cannot bind UWB radio controller:"
+                               " %d\n", err);
+                       goto error_bind;
+               }
+               if (err < 0)
+                       dev_warn(&pci->dev, "warning: cannot bind capability "
+                                "#%u: %d\n", n, err);
+       }
+       pci_set_drvdata(pci, card);
+       return 0;
+
+error_bind:
+       pci_iounmap(pci, card->uwbbase);
+error_iomap:
+       release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
+error_request_memregion:
+       kfree(card);
+error_kzalloc:
+error_ncaps:
+error_dma:
+       pci_disable_msi(pci);
+       pci_disable_device(pci);
+error:
+       return err;
+}
+
+static void whci_remove(struct pci_dev *pci)
+{
+       struct whci_card *card = pci_get_drvdata(pci);
+       int n;
+
+       pci_set_drvdata(pci, NULL);
+       /* Unregister each capability in reverse (so the master device
+        * is unregistered last). */
+       for (n = card->n_caps; n >= 0 ; n--)
+               whci_del_cap(card, n);
+       pci_iounmap(pci, card->uwbbase);
+       release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
+       kfree(card);
+       pci_disable_msi(pci);
+       pci_disable_device(pci);
+}
+
+static struct pci_device_id whci_id_table[] = {
+       { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
+       { 0 },
+};
+MODULE_DEVICE_TABLE(pci, whci_id_table);
+
+
+static struct pci_driver whci_driver = {
+       .name     = "whci",
+       .id_table = whci_id_table,
+       .probe    = whci_probe,
+       .remove   = whci_remove,
+};
+
+module_pci_driver(whci_driver);
+MODULE_DESCRIPTION("WHCI UWB Multi-interface Controller enumerator");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/Documentation/wusb-cbaf b/drivers/staging/wusbcore/Documentation/wusb-cbaf
new file mode 100644 (file)
index 0000000..8b3d43e
--- /dev/null
@@ -0,0 +1,130 @@
+#! /bin/bash
+#
+
+set -e
+
+progname=$(basename $0)
+function help
+{
+    cat <<EOF
+Usage: $progname COMMAND DEVICEs [ARGS]
+
+Command for manipulating the pairing/authentication credentials of a
+Wireless USB device that supports wired-mode Cable-Based-Association.
+
+Works in conjunction with the wusb-cba.ko driver from http://linuxuwb.org.
+
+
+DEVICE
+
+ sysfs path to the device to authenticate; for example, both this
+ guys are the same:
+
+ /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4.4/1-4.4:1.1
+ /sys/bus/usb/drivers/wusb-cbaf/1-4.4:1.1
+
+COMMAND/ARGS are
+
+ start
+
+   Start a WUSB host controller (by setting up a CHID)
+
+ set-chid DEVICE HOST-CHID HOST-BANDGROUP HOST-NAME
+
+   Sets host information in the device; after this you can call the
+   get-cdid to see how does this device report itself to us.
+
+ get-cdid DEVICE
+
+   Get the device ID associated to the HOST-CHID we sent with
+   'set-chid'. We might not know about it.
+
+ set-cc DEVICE
+
+   If we allow the device to connect, set a random new CDID and CK
+   (connection key). Device saves them for the next time it wants to
+   connect wireless. We save them for that next time also so we can
+   authenticate the device (when we see the CDID he uses to id
+   itself) and the CK to crypto talk to it.
+
+CHID is always 16 hex bytes in 'XX YY ZZ...' form
+BANDGROUP is almost always 0001
+
+Examples:
+
+  You can default most arguments to '' to get a sane value:
+
+  $ $progname set-chid '' '' '' "My host name"
+
+  A full sequence:
+
+  $ $progname set-chid '' '' '' "My host name"
+  $ $progname get-cdid ''
+  $ $progname set-cc ''
+
+EOF
+}
+
+
+# Defaults
+# FIXME: CHID should come from a database :), band group from the host
+host_CHID="00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff"
+host_band_group="0001"
+host_name=$(hostname)
+
+devs="$(echo /sys/bus/usb/drivers/wusb-cbaf/[0-9]*)"
+hdevs="$(for h in /sys/class/uwb_rc/*/wusbhc; do readlink -f $h; done)"
+
+result=0
+case $1 in
+    start)
+        for dev in ${2:-$hdevs}
+          do
+          echo $host_CHID > $dev/wusb_chid
+          echo I: started host $(basename $dev) >&2
+        done
+        ;;
+    stop)
+        for dev in ${2:-$hdevs}
+          do
+          echo 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 > $dev/wusb_chid
+          echo I: stopped host $(basename $dev) >&2
+        done
+        ;;
+    set-chid)
+        shift
+        for dev in ${2:-$devs}; do
+            echo "${4:-$host_name}" > $dev/wusb_host_name
+            echo "${3:-$host_band_group}" > $dev/wusb_host_band_groups
+            echo ${2:-$host_CHID} > $dev/wusb_chid
+        done
+        ;;
+    get-cdid)
+        for dev in ${2:-$devs}
+          do
+          cat $dev/wusb_cdid
+        done
+        ;;
+    set-cc)
+        for dev in ${2:-$devs}; do
+            shift
+            CDID="$(head --bytes=16 /dev/urandom  | od -tx1 -An)"
+            CK="$(head --bytes=16 /dev/urandom  | od -tx1 -An)"
+            echo "$CDID" > $dev/wusb_cdid
+            echo "$CK" > $dev/wusb_ck
+
+            echo I: CC set >&2
+            echo "CHID: $(cat $dev/wusb_chid)"
+            echo "CDID:$CDID"
+            echo "CK:  $CK"
+        done
+        ;;
+    help|h|--help|-h)
+        help
+        ;;
+    *)
+        echo "E: Unknown usage" 1>&2
+        help 1>&2
+        result=1
+esac
+exit $result
diff --git a/drivers/staging/wusbcore/Documentation/wusb-design-overview.rst b/drivers/staging/wusbcore/Documentation/wusb-design-overview.rst
new file mode 100644 (file)
index 0000000..dc5e216
--- /dev/null
@@ -0,0 +1,457 @@
+================================
+Linux UWB + Wireless USB + WiNET
+================================
+
+   Copyright (C) 2005-2006 Intel Corporation
+
+   Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License version
+   2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+
+Please visit http://bughost.org/thewiki/Design-overview.txt-1.8 for
+updated content.
+
+    * Design-overview.txt-1.8
+
+This code implements a Ultra Wide Band stack for Linux, as well as
+drivers for the USB based UWB radio controllers defined in the
+Wireless USB 1.0 specification (including Wireless USB host controller
+and an Intel WiNET controller).
+
+.. Contents
+   1. Introduction
+         1. HWA: Host Wire adapters, your Wireless USB dongle
+
+         2. DWA: Device Wired Adaptor, a Wireless USB hub for wired
+            devices
+         3. WHCI: Wireless Host Controller Interface, the PCI WUSB host
+            adapter
+   2. The UWB stack
+         1. Devices and hosts: the basic structure
+
+         2. Host Controller life cycle
+
+         3. On the air: beacons and enumerating the radio neighborhood
+
+         4. Device lists
+         5. Bandwidth allocation
+
+   3. Wireless USB Host Controller drivers
+
+   4. Glossary
+
+
+Introduction
+============
+
+UWB is a wide-band communication protocol that is to serve also as the
+low-level protocol for others (much like TCP sits on IP). Currently
+these others are Wireless USB and TCP/IP, but seems Bluetooth and
+Firewire/1394 are coming along.
+
+UWB uses a band from roughly 3 to 10 GHz, transmitting at a max of
+~-41dB (or 0.074 uW/MHz--geography specific data is still being
+negotiated w/ regulators, so watch for changes). That band is divided in
+a bunch of ~1.5 GHz wide channels (or band groups) composed of three
+subbands/subchannels (528 MHz each). Each channel is independent of each
+other, so you could consider them different "busses". Initially this
+driver considers them all a single one.
+
+Radio time is divided in 65536 us long /superframes/, each one divided
+in 256 256us long /MASs/ (Media Allocation Slots), which are the basic
+time/media allocation units for transferring data. At the beginning of
+each superframe there is a Beacon Period (BP), where every device
+transmit its beacon on a single MAS. The length of the BP depends on how
+many devices are present and the length of their beacons.
+
+Devices have a MAC (fixed, 48 bit address) and a device (changeable, 16
+bit address) and send periodic beacons to advertise themselves and pass
+info on what they are and do. They advertise their capabilities and a
+bunch of other stuff.
+
+The different logical parts of this driver are:
+
+    *
+
+      *UWB*: the Ultra-Wide-Band stack -- manages the radio and
+      associated spectrum to allow for devices sharing it. Allows to
+      control bandwidth assignment, beaconing, scanning, etc
+
+    *
+
+      *WUSB*: the layer that sits on top of UWB to provide Wireless USB.
+      The Wireless USB spec defines means to control a UWB radio and to
+      do the actual WUSB.
+
+
+HWA: Host Wire adapters, your Wireless USB dongle
+-------------------------------------------------
+
+WUSB also defines a device called a Host Wire Adaptor (HWA), which in
+mere terms is a USB dongle that enables your PC to have UWB and Wireless
+USB. The Wireless USB Host Controller in a HWA looks to the host like a
+[Wireless] USB controller connected via USB (!)
+
+The HWA itself is broken in two or three main interfaces:
+
+    *
+
+      *RC*: Radio control -- this implements an interface to the
+      Ultra-Wide-Band radio controller. The driver for this implements a
+      USB-based UWB Radio Controller to the UWB stack.
+
+    *
+
+      *HC*: the wireless USB host controller. It looks like a USB host
+      whose root port is the radio and the WUSB devices connect to it.
+      To the system it looks like a separate USB host. The driver (will)
+      implement a USB host controller (similar to UHCI, OHCI or EHCI)
+      for which the root hub is the radio...To reiterate: it is a USB
+      controller that is connected via USB instead of PCI.
+
+    *
+
+      *WINET*: some HW provide a WiNET interface (IP over UWB). This
+      package provides a driver for it (it looks like a network
+      interface, winetX). The driver detects when there is a link up for
+      their type and kick into gear.
+
+
+DWA: Device Wired Adaptor, a Wireless USB hub for wired devices
+---------------------------------------------------------------
+
+These are the complement to HWAs. They are a USB host for connecting
+wired devices, but it is connected to your PC connected via Wireless
+USB. To the system it looks like yet another USB host. To the untrained
+eye, it looks like a hub that connects upstream wirelessly.
+
+We still offer no support for this; however, it should share a lot of
+code with the HWA-RC driver; there is a bunch of factorization work that
+has been done to support that in upcoming releases.
+
+
+WHCI: Wireless Host Controller Interface, the PCI WUSB host adapter
+-------------------------------------------------------------------
+
+This is your usual PCI device that implements WHCI. Similar in concept
+to EHCI, it allows your wireless USB devices (including DWAs) to connect
+to your host via a PCI interface. As in the case of the HWA, it has a
+Radio Control interface and the WUSB Host Controller interface per se.
+
+There is still no driver support for this, but will be in upcoming
+releases.
+
+
+The UWB stack
+=============
+
+The main mission of the UWB stack is to keep a tally of which devices
+are in radio proximity to allow drivers to connect to them. As well, it
+provides an API for controlling the local radio controllers (RCs from
+now on), such as to start/stop beaconing, scan, allocate bandwidth, etc.
+
+
+Devices and hosts: the basic structure
+--------------------------------------
+
+The main building block here is the UWB device (struct uwb_dev). For
+each device that pops up in radio presence (ie: the UWB host receives a
+beacon from it) you get a struct uwb_dev that will show up in
+/sys/bus/uwb/devices.
+
+For each RC that is detected, a new struct uwb_rc and struct uwb_dev are
+created. An entry is also created in /sys/class/uwb_rc for each RC.
+
+Each RC driver is implemented by a separate driver that plugs into the
+interface that the UWB stack provides through a struct uwb_rc_ops. The
+spec creators have been nice enough to make the message format the same
+for HWA and WHCI RCs, so the driver is really a very thin transport that
+moves the requests from the UWB API to the device [/uwb_rc_ops->cmd()/]
+and sends the replies and notifications back to the API
+[/uwb_rc_neh_grok()/]. Notifications are handled to the UWB daemon, that
+is chartered, among other things, to keep the tab of how the UWB radio
+neighborhood looks, creating and destroying devices as they show up or
+disappear.
+
+Command execution is very simple: a command block is sent and a event
+block or reply is expected back. For sending/receiving command/events, a
+handle called /neh/ (Notification/Event Handle) is opened with
+/uwb_rc_neh_open()/.
+
+The HWA-RC (USB dongle) driver (drivers/uwb/hwa-rc.c) does this job for
+the USB connected HWA. Eventually, drivers/whci-rc.c will do the same
+for the PCI connected WHCI controller.
+
+
+Host Controller life cycle
+--------------------------
+
+So let's say we connect a dongle to the system: it is detected and
+firmware uploaded if needed [for Intel's i1480
+/drivers/uwb/ptc/usb.c:ptc_usb_probe()/] and then it is reenumerated.
+Now we have a real HWA device connected and
+/drivers/uwb/hwa-rc.c:hwarc_probe()/ picks it up, that will set up the
+Wire-Adaptor environment and then suck it into the UWB stack's vision of
+the world [/drivers/uwb/lc-rc.c:uwb_rc_add()/].
+
+    *
+
+      [*] The stack should put a new RC to scan for devices
+      [/uwb_rc_scan()/] so it finds what's available around and tries to
+      connect to them, but this is policy stuff and should be driven
+      from user space. As of now, the operator is expected to do it
+      manually; see the release notes for documentation on the procedure.
+
+When a dongle is disconnected, /drivers/uwb/hwa-rc.c:hwarc_disconnect()/
+takes time of tearing everything down safely (or not...).
+
+
+On the air: beacons and enumerating the radio neighborhood
+----------------------------------------------------------
+
+So assuming we have devices and we have agreed for a channel to connect
+on (let's say 9), we put the new RC to beacon:
+
+    *
+
+            $ echo 9 0 > /sys/class/uwb_rc/uwb0/beacon
+
+Now it is visible. If there were other devices in the same radio channel
+and beacon group (that's what the zero is for), the dongle's radio
+control interface will send beacon notifications on its
+notification/event endpoint (NEEP). The beacon notifications are part of
+the event stream that is funneled into the API with
+/drivers/uwb/neh.c:uwb_rc_neh_grok()/ and delivered to the UWBD, the UWB
+daemon through a notification list.
+
+UWBD wakes up and scans the event list; finds a beacon and adds it to
+the BEACON CACHE (/uwb_beca/). If he receives a number of beacons from
+the same device, he considers it to be 'onair' and creates a new device
+[/drivers/uwb/lc-dev.c:uwbd_dev_onair()/]. Similarly, when no beacons
+are received in some time, the device is considered gone and wiped out
+[uwbd calls periodically /uwb/beacon.c:uwb_beca_purge()/ that will purge
+the beacon cache of dead devices].
+
+
+Device lists
+------------
+
+All UWB devices are kept in the list of the struct bus_type uwb_bus_type.
+
+
+Bandwidth allocation
+--------------------
+
+The UWB stack maintains a local copy of DRP availability through
+processing of incoming *DRP Availability Change* notifications. This
+local copy is currently used to present the current bandwidth
+availability to the user through the sysfs file
+/sys/class/uwb_rc/uwbx/bw_avail. In the future the bandwidth
+availability information will be used by the bandwidth reservation
+routines.
+
+The bandwidth reservation routines are in progress and are thus not
+present in the current release. When completed they will enable a user
+to initiate DRP reservation requests through interaction with sysfs. DRP
+reservation requests from remote UWB devices will also be handled. The
+bandwidth management done by the UWB stack will include callbacks to the
+higher layers will enable the higher layers to use the reservations upon
+completion. [Note: The bandwidth reservation work is in progress and
+subject to change.]
+
+
+Wireless USB Host Controller drivers
+====================================
+
+*WARNING* This section needs a lot of work!
+
+As explained above, there are three different types of HCs in the WUSB
+world: HWA-HC, DWA-HC and WHCI-HC.
+
+HWA-HC and DWA-HC share that they are Wire-Adapters (USB or WUSB
+connected controllers), and their transfer management system is almost
+identical. So is their notification delivery system.
+
+HWA-HC and WHCI-HC share that they are both WUSB host controllers, so
+they have to deal with WUSB device life cycle and maintenance, wireless
+root-hub
+
+HWA exposes a Host Controller interface (HWA-HC 0xe0/02/02). This has
+three endpoints (Notifications, Data Transfer In and Data Transfer
+Out--known as NEP, DTI and DTO in the code).
+
+We reserve UWB bandwidth for our Wireless USB Cluster, create a Cluster
+ID and tell the HC to use all that. Then we start it. This means the HC
+starts sending MMCs.
+
+    *
+
+      The MMCs are blocks of data defined somewhere in the WUSB1.0 spec
+      that define a stream in the UWB channel time allocated for sending
+      WUSB IEs (host to device commands/notifications) and Device
+      Notifications (device initiated to host). Each host defines a
+      unique Wireless USB cluster through MMCs. Devices can connect to a
+      single cluster at the time. The IEs are Information Elements, and
+      among them are the bandwidth allocations that tell each device
+      when can they transmit or receive.
+
+Now it all depends on external stimuli.
+
+New device connection
+---------------------
+
+A new device pops up, it scans the radio looking for MMCs that give out
+the existence of Wireless USB channels. Once one (or more) are found,
+selects which one to connect to. Sends a /DN_Connect/ (device
+notification connect) during the DNTS (Device Notification Time
+Slot--announced in the MMCs
+
+HC picks the /DN_Connect/ out (nep module sends to notif.c for delivery
+into /devconnect/). This process starts the authentication process for
+the device. First we allocate a /fake port/ and assign an
+unauthenticated address (128 to 255--what we really do is
+0x80 | fake_port_idx). We fiddle with the fake port status and /hub_wq/
+sees a new connection, so he moves on to enable the fake port with a reset.
+
+So now we are in the reset path -- we know we have a non-yet enumerated
+device with an unauthorized address; we ask user space to authenticate
+(FIXME: not yet done, similar to bluetooth pairing), then we do the key
+exchange (FIXME: not yet done) and issue a /set address 0/ to bring the
+device to the default state. Device is authenticated.
+
+From here, the USB stack takes control through the usb_hcd ops. hub_wq
+has seen the port status changes, as we have been toggling them. It will
+start enumerating and doing transfers through usb_hcd->urb_enqueue() to
+read descriptors and move our data.
+
+Device life cycle and keep alives
+---------------------------------
+
+Every time there is a successful transfer to/from a device, we update a
+per-device activity timestamp. If not, every now and then we check and
+if the activity timestamp gets old, we ping the device by sending it a
+Keep Alive IE; it responds with a /DN_Alive/ pong during the DNTS (this
+arrives to us as a notification through
+devconnect.c:wusb_handle_dn_alive(). If a device times out, we
+disconnect it from the system (cleaning up internal information and
+toggling the bits in the fake hub port, which kicks hub_wq into removing
+the rest of the stuff).
+
+This is done through devconnect:__wusb_check_devs(), which will scan the
+device list looking for whom needs refreshing.
+
+If the device wants to disconnect, it will either die (ugly) or send a
+/DN_Disconnect/ that will prompt a disconnection from the system.
+
+Sending and receiving data
+--------------------------
+
+Data is sent and received through /Remote Pipes/ (rpipes). An rpipe is
+/aimed/ at an endpoint in a WUSB device. This is the same for HWAs and
+DWAs.
+
+Each HC has a number of rpipes and buffers that can be assigned to them;
+when doing a data transfer (xfer), first the rpipe has to be aimed and
+prepared (buffers assigned), then we can start queueing requests for
+data in or out.
+
+Data buffers have to be segmented out before sending--so we send first a
+header (segment request) and then if there is any data, a data buffer
+immediately after to the DTI interface (yep, even the request). If our
+buffer is bigger than the max segment size, then we just do multiple
+requests.
+
+[This sucks, because doing USB scatter gatter in Linux is resource
+intensive, if any...not that the current approach is not. It just has to
+be cleaned up a lot :)].
+
+If reading, we don't send data buffers, just the segment headers saying
+we want to read segments.
+
+When the xfer is executed, we receive a notification that says data is
+ready in the DTI endpoint (handled through
+xfer.c:wa_handle_notif_xfer()). In there we read from the DTI endpoint a
+descriptor that gives us the status of the transfer, its identification
+(given when we issued it) and the segment number. If it was a data read,
+we issue another URB to read into the destination buffer the chunk of
+data coming out of the remote endpoint. Done, wait for the next guy. The
+callbacks for the URBs issued from here are the ones that will declare
+the xfer complete at some point and call its callback.
+
+Seems simple, but the implementation is not trivial.
+
+    *
+
+      *WARNING* Old!!
+
+The main xfer descriptor, wa_xfer (equivalent to a URB) contains an
+array of segments, tallys on segments and buffers and callback
+information. Buried in there is a lot of URBs for executing the segments
+and buffer transfers.
+
+For OUT xfers, there is an array of segments, one URB for each, another
+one of buffer URB. When submitting, we submit URBs for segment request
+1, buffer 1, segment 2, buffer 2...etc. Then we wait on the DTI for xfer
+result data; when all the segments are complete, we call the callback to
+finalize the transfer.
+
+For IN xfers, we only issue URBs for the segments we want to read and
+then wait for the xfer result data.
+
+URB mapping into xfers
+^^^^^^^^^^^^^^^^^^^^^^
+
+This is done by hwahc_op_urb_[en|de]queue(). In enqueue() we aim an
+rpipe to the endpoint where we have to transmit, create a transfer
+context (wa_xfer) and submit it. When the xfer is done, our callback is
+called and we assign the status bits and release the xfer resources.
+
+In dequeue() we are basically cancelling/aborting the transfer. We issue
+a xfer abort request to the HC, cancel all the URBs we had submitted
+and not yet done and when all that is done, the xfer callback will be
+called--this will call the URB callback.
+
+
+Glossary
+========
+
+*DWA* -- Device Wire Adapter
+
+USB host, wired for downstream devices, upstream connects wirelessly
+with Wireless USB.
+
+*EVENT* -- Response to a command on the NEEP
+
+*HWA* -- Host Wire Adapter / USB dongle for UWB and Wireless USB
+
+*NEH* -- Notification/Event Handle
+
+Handle/file descriptor for receiving notifications or events. The WA
+code requires you to get one of this to listen for notifications or
+events on the NEEP.
+
+*NEEP* -- Notification/Event EndPoint
+
+Stuff related to the management of the first endpoint of a HWA USB
+dongle that is used to deliver an stream of events and notifications to
+the host.
+
+*NOTIFICATION* -- Message coming in the NEEP as response to something.
+
+*RC* -- Radio Control
+
+Design-overview.txt-1.8 (last edited 2006-11-04 12:22:24 by
+InakyPerezGonzalez)
diff --git a/drivers/staging/wusbcore/Kconfig b/drivers/staging/wusbcore/Kconfig
new file mode 100644 (file)
index 0000000..056c60b
--- /dev/null
@@ -0,0 +1,39 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Wireless USB Core configuration
+#
+config USB_WUSB
+       tristate "Enable Wireless USB extensions"
+       depends on UWB
+       select CRYPTO
+       select CRYPTO_AES
+       select CRYPTO_CCM
+       help
+         Enable the host-side support for Wireless USB.
+
+          To compile this support select Y (built in). It is safe to
+         select even if you don't have the hardware.
+
+config USB_WUSB_CBAF
+       tristate "Support WUSB Cable Based Association (CBA)"
+       depends on USB
+       help
+         Some WUSB devices support Cable Based Association. It's used to
+         enable the secure communication between the host and the
+         device.
+
+         Enable this option if your WUSB device must to be connected
+         via wired USB before establishing a wireless link.
+
+         It is safe to select even if you don't have a compatible
+         hardware.
+
+config USB_WUSB_CBAF_DEBUG
+       bool "Enable CBA debug messages"
+       depends on USB_WUSB_CBAF
+       help
+         Say Y here if you want the CBA to produce a bunch of debug messages
+         to the system log. Select this if you are having a problem with
+         CBA support and want to see more of what is going on.
+
+source "drivers/staging/wusbcore/host/Kconfig"
diff --git a/drivers/staging/wusbcore/Makefile b/drivers/staging/wusbcore/Makefile
new file mode 100644 (file)
index 0000000..b47b874
--- /dev/null
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+ccflags-$(CONFIG_USB_WUSB_CBAF_DEBUG) := -DDEBUG
+
+obj-$(CONFIG_USB_WUSB)         += wusbcore.o
+obj-$(CONFIG_USB_HWA_HCD)      += wusb-wa.o
+obj-$(CONFIG_USB_WUSB_CBAF)    += wusb-cbaf.o
+
+
+wusbcore-y :=          \
+       crypto.o        \
+       devconnect.o    \
+       dev-sysfs.o     \
+       mmc.o           \
+       pal.o           \
+       rh.o            \
+       reservation.o   \
+       security.o      \
+       wusbhc.o
+
+wusb-cbaf-y := cbaf.o
+
+wusb-wa-y :=           \
+       wa-hc.o         \
+       wa-nep.o        \
+       wa-rpipe.o      \
+       wa-xfer.o
+
+obj-y  += host/
diff --git a/drivers/staging/wusbcore/TODO b/drivers/staging/wusbcore/TODO
new file mode 100644 (file)
index 0000000..abae570
--- /dev/null
@@ -0,0 +1,8 @@
+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>
diff --git a/drivers/staging/wusbcore/cbaf.c b/drivers/staging/wusbcore/cbaf.c
new file mode 100644 (file)
index 0000000..57062ea
--- /dev/null
@@ -0,0 +1,645 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB - Cable Based Association
+ *
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ *
+ * WUSB devices have to be paired (associated in WUSB lingo) so
+ * that they can connect to the system.
+ *
+ * One way of pairing is using CBA-Cable Based Association. First
+ * time you plug the device with a cable, association is done between
+ * host and device and subsequent times, you can connect wirelessly
+ * without having to associate again. That's the idea.
+ *
+ * This driver does nothing Earth shattering. It just provides an
+ * interface to chat with the wire-connected device so we can get a
+ * CDID (device ID) that might have been previously associated to a
+ * CHID (host ID) and to set up a new <CHID,CDID,CK> triplet
+ * (connection context), with the CK being the secret, or connection
+ * key. This is the pairing data.
+ *
+ * When a device with the CBA capability connects, the probe routine
+ * just creates a bunch of sysfs files that a user space enumeration
+ * manager uses to allow it to connect wirelessly to the system or not.
+ *
+ * The process goes like this:
+ *
+ * 1. Device plugs, cbaf is loaded, notifications happen.
+ *
+ * 2. The connection manager (CM) sees a device with CBAF capability
+ *    (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE).
+ *
+ * 3. The CM writes the host name, supported band groups, and the CHID
+ *    (host ID) into the wusb_host_name, wusb_host_band_groups and
+ *    wusb_chid files. These get sent to the device and the CDID (if
+ *    any) for this host is requested.
+ *
+ * 4. The CM can verify that the device's supported band groups
+ *    (wusb_device_band_groups) are compatible with the host.
+ *
+ * 5. The CM reads the wusb_cdid file.
+ *
+ * 6. The CM looks up its database
+ *
+ * 6.1 If it has a matching CHID,CDID entry, the device has been
+ *     authorized before (paired) and nothing further needs to be
+ *     done.
+ *
+ * 6.2 If the CDID is zero (or the CM doesn't find a matching CDID in
+ *     its database), the device is assumed to be not known.  The CM
+ *     may associate the host with device by: writing a randomly
+ *     generated CDID to wusb_cdid and then a random CK to wusb_ck
+ *     (this uploads the new CC to the device).
+ *
+ *     CMD may choose to prompt the user before associating with a new
+ *     device.
+ *
+ * 7. Device is unplugged.
+ *
+ * When the device tries to connect wirelessly, it will present its
+ * CDID to the WUSB host controller.  The CM will query the
+ * database. If the CHID/CDID pair found, it will (with a 4-way
+ * handshake) challenge the device to demonstrate it has the CK secret
+ * key (from our database) without actually exchanging it. Once
+ * satisfied, crypto keys are derived from the CK, the device is
+ * connected and all communication is encrypted.
+ *
+ * References:
+ *   [WUSB-AM] Association Models Supplement to the Certified Wireless
+ *             Universal Serial Bus Specification, version 1.0.
+ */
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/usb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include "../uwb/uwb.h"
+#include "include/wusb.h"
+#include "include/association.h"
+
+#define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */
+
+/* An instance of a Cable-Based-Association-Framework device */
+struct cbaf {
+       struct usb_device *usb_dev;
+       struct usb_interface *usb_iface;
+       void *buffer;
+       size_t buffer_size;
+
+       struct wusb_ckhdid chid;
+       char host_name[CBA_NAME_LEN];
+       u16 host_band_groups;
+
+       struct wusb_ckhdid cdid;
+       char device_name[CBA_NAME_LEN];
+       u16 device_band_groups;
+
+       struct wusb_ckhdid ck;
+};
+
+/*
+ * Verify that a CBAF USB-interface has what we need
+ *
+ * According to [WUSB-AM], CBA devices should provide at least two
+ * interfaces:
+ *  - RETRIEVE_HOST_INFO
+ *  - ASSOCIATE
+ *
+ * If the device doesn't provide these interfaces, we do not know how
+ * to deal with it.
+ */
+static int cbaf_check(struct cbaf *cbaf)
+{
+       int result;
+       struct device *dev = &cbaf->usb_iface->dev;
+       struct wusb_cbaf_assoc_info *assoc_info;
+       struct wusb_cbaf_assoc_request *assoc_request;
+       size_t assoc_size;
+       void *itr, *top;
+       int ar_rhi = 0, ar_assoc = 0;
+
+       result = usb_control_msg(
+               cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
+               CBAF_REQ_GET_ASSOCIATION_INFORMATION,
+               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+               cbaf->buffer, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT);
+       if (result < 0) {
+               dev_err(dev, "Cannot get available association types: %d\n",
+                       result);
+               return result;
+       }
+
+       assoc_info = cbaf->buffer;
+       if (result < sizeof(*assoc_info)) {
+               dev_err(dev, "Not enough data to decode association info "
+                       "header (%zu vs %zu bytes required)\n",
+                       (size_t)result, sizeof(*assoc_info));
+               return result;
+       }
+
+       assoc_size = le16_to_cpu(assoc_info->Length);
+       if (result < assoc_size) {
+               dev_err(dev, "Not enough data to decode association info "
+                       "(%zu vs %zu bytes required)\n",
+                       (size_t)assoc_size, sizeof(*assoc_info));
+               return result;
+       }
+       /*
+        * From now on, we just verify, but won't error out unless we
+        * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE}
+        * types.
+        */
+       itr = cbaf->buffer + sizeof(*assoc_info);
+       top = cbaf->buffer + assoc_size;
+       dev_dbg(dev, "Found %u association requests (%zu bytes)\n",
+                assoc_info->NumAssociationRequests, assoc_size);
+
+       while (itr < top) {
+               u16 ar_type, ar_subtype;
+               u32 ar_size;
+               const char *ar_name;
+
+               assoc_request = itr;
+
+               if (top - itr < sizeof(*assoc_request)) {
+                       dev_err(dev, "Not enough data to decode association "
+                               "request (%zu vs %zu bytes needed)\n",
+                               top - itr, sizeof(*assoc_request));
+                       break;
+               }
+
+               ar_type = le16_to_cpu(assoc_request->AssociationTypeId);
+               ar_subtype = le16_to_cpu(assoc_request->AssociationSubTypeId);
+               ar_size = le32_to_cpu(assoc_request->AssociationTypeInfoSize);
+               ar_name = "unknown";
+
+               switch (ar_type) {
+               case AR_TYPE_WUSB:
+                       /* Verify we have what is mandated by [WUSB-AM]. */
+                       switch (ar_subtype) {
+                       case AR_TYPE_WUSB_RETRIEVE_HOST_INFO:
+                               ar_name = "RETRIEVE_HOST_INFO";
+                               ar_rhi = 1;
+                               break;
+                       case AR_TYPE_WUSB_ASSOCIATE:
+                               /* send assoc data */
+                               ar_name = "ASSOCIATE";
+                               ar_assoc = 1;
+                               break;
+                       }
+                       break;
+               }
+
+               dev_dbg(dev, "Association request #%02u: 0x%04x/%04x "
+                        "(%zu bytes): %s\n",
+                        assoc_request->AssociationDataIndex, ar_type,
+                        ar_subtype, (size_t)ar_size, ar_name);
+
+               itr += sizeof(*assoc_request);
+       }
+
+       if (!ar_rhi) {
+               dev_err(dev, "Missing RETRIEVE_HOST_INFO association "
+                       "request\n");
+               return -EINVAL;
+       }
+       if (!ar_assoc) {
+               dev_err(dev, "Missing ASSOCIATE association request\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static const struct wusb_cbaf_host_info cbaf_host_info_defaults = {
+       .AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId,
+       .AssociationTypeId        = cpu_to_le16(AR_TYPE_WUSB),
+       .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
+       .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO),
+       .CHID_hdr                 = WUSB_AR_CHID,
+       .LangID_hdr               = WUSB_AR_LangID,
+       .HostFriendlyName_hdr     = WUSB_AR_HostFriendlyName,
+};
+
+/* Send WUSB host information (CHID and name) to a CBAF device */
+static int cbaf_send_host_info(struct cbaf *cbaf)
+{
+       struct wusb_cbaf_host_info *hi;
+       size_t name_len;
+       size_t hi_size;
+
+       hi = cbaf->buffer;
+       memset(hi, 0, sizeof(*hi));
+       *hi = cbaf_host_info_defaults;
+       hi->CHID = cbaf->chid;
+       hi->LangID = 0; /* FIXME: I guess... */
+       strlcpy(hi->HostFriendlyName, cbaf->host_name, CBA_NAME_LEN);
+       name_len = strlen(cbaf->host_name);
+       hi->HostFriendlyName_hdr.len = cpu_to_le16(name_len);
+       hi_size = sizeof(*hi) + name_len;
+
+       return usb_control_msg(cbaf->usb_dev,
+                       usb_sndctrlpipe(cbaf->usb_dev, 0),
+                       CBAF_REQ_SET_ASSOCIATION_RESPONSE,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       0x0101,
+                       cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+                       hi, hi_size, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * Get device's information (CDID) associated to CHID
+ *
+ * The device will return it's information (CDID, name, bandgroups)
+ * associated to the CHID we have set before, or 0 CDID and default
+ * name and bandgroup if no CHID set or unknown.
+ */
+static int cbaf_cdid_get(struct cbaf *cbaf)
+{
+       int result;
+       struct device *dev = &cbaf->usb_iface->dev;
+       struct wusb_cbaf_device_info *di;
+       size_t needed;
+
+       di = cbaf->buffer;
+       result = usb_control_msg(
+               cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
+               CBAF_REQ_GET_ASSOCIATION_REQUEST,
+               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+               di, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT);
+       if (result < 0) {
+               dev_err(dev, "Cannot request device information: %d\n",
+                       result);
+               return result;
+       }
+
+       needed = result < sizeof(*di) ? sizeof(*di) : le32_to_cpu(di->Length);
+       if (result < needed) {
+               dev_err(dev, "Not enough data in DEVICE_INFO reply (%zu vs "
+                       "%zu bytes needed)\n", (size_t)result, needed);
+               return -ENOENT;
+       }
+
+       strlcpy(cbaf->device_name, di->DeviceFriendlyName, CBA_NAME_LEN);
+       cbaf->cdid = di->CDID;
+       cbaf->device_band_groups = le16_to_cpu(di->BandGroups);
+
+       return 0;
+}
+
+static ssize_t cbaf_wusb_chid_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+
+       return sprintf(buf, "%16ph\n", cbaf->chid.data);
+}
+
+static ssize_t cbaf_wusb_chid_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t size)
+{
+       ssize_t result;
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+
+       result = sscanf(buf,
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx",
+                       &cbaf->chid.data[0] , &cbaf->chid.data[1],
+                       &cbaf->chid.data[2] , &cbaf->chid.data[3],
+                       &cbaf->chid.data[4] , &cbaf->chid.data[5],
+                       &cbaf->chid.data[6] , &cbaf->chid.data[7],
+                       &cbaf->chid.data[8] , &cbaf->chid.data[9],
+                       &cbaf->chid.data[10], &cbaf->chid.data[11],
+                       &cbaf->chid.data[12], &cbaf->chid.data[13],
+                       &cbaf->chid.data[14], &cbaf->chid.data[15]);
+
+       if (result != 16)
+               return -EINVAL;
+
+       result = cbaf_send_host_info(cbaf);
+       if (result < 0)
+               return result;
+       result = cbaf_cdid_get(cbaf);
+       if (result < 0)
+               return result;
+       return size;
+}
+static DEVICE_ATTR(wusb_chid, 0600, cbaf_wusb_chid_show, cbaf_wusb_chid_store);
+
+static ssize_t cbaf_wusb_host_name_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+
+       return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->host_name);
+}
+
+static ssize_t cbaf_wusb_host_name_store(struct device *dev,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t size)
+{
+       ssize_t result;
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+
+       result = sscanf(buf, "%63s", cbaf->host_name);
+       if (result != 1)
+               return -EINVAL;
+
+       return size;
+}
+static DEVICE_ATTR(wusb_host_name, 0600, cbaf_wusb_host_name_show,
+                                        cbaf_wusb_host_name_store);
+
+static ssize_t cbaf_wusb_host_band_groups_show(struct device *dev,
+                                              struct device_attribute *attr,
+                                              char *buf)
+{
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+
+       return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->host_band_groups);
+}
+
+static ssize_t cbaf_wusb_host_band_groups_store(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t size)
+{
+       ssize_t result;
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+       u16 band_groups = 0;
+
+       result = sscanf(buf, "%04hx", &band_groups);
+       if (result != 1)
+               return -EINVAL;
+
+       cbaf->host_band_groups = band_groups;
+
+       return size;
+}
+
+static DEVICE_ATTR(wusb_host_band_groups, 0600,
+                  cbaf_wusb_host_band_groups_show,
+                  cbaf_wusb_host_band_groups_store);
+
+static const struct wusb_cbaf_device_info cbaf_device_info_defaults = {
+       .Length_hdr               = WUSB_AR_Length,
+       .CDID_hdr                 = WUSB_AR_CDID,
+       .BandGroups_hdr           = WUSB_AR_BandGroups,
+       .LangID_hdr               = WUSB_AR_LangID,
+       .DeviceFriendlyName_hdr   = WUSB_AR_DeviceFriendlyName,
+};
+
+static ssize_t cbaf_wusb_cdid_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+
+       return sprintf(buf, "%16ph\n", cbaf->cdid.data);
+}
+
+static ssize_t cbaf_wusb_cdid_store(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t size)
+{
+       ssize_t result;
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+       struct wusb_ckhdid cdid;
+
+       result = sscanf(buf,
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx",
+                       &cdid.data[0] , &cdid.data[1],
+                       &cdid.data[2] , &cdid.data[3],
+                       &cdid.data[4] , &cdid.data[5],
+                       &cdid.data[6] , &cdid.data[7],
+                       &cdid.data[8] , &cdid.data[9],
+                       &cdid.data[10], &cdid.data[11],
+                       &cdid.data[12], &cdid.data[13],
+                       &cdid.data[14], &cdid.data[15]);
+       if (result != 16)
+               return -EINVAL;
+
+       cbaf->cdid = cdid;
+
+       return size;
+}
+static DEVICE_ATTR(wusb_cdid, 0600, cbaf_wusb_cdid_show, cbaf_wusb_cdid_store);
+
+static ssize_t cbaf_wusb_device_band_groups_show(struct device *dev,
+                                                struct device_attribute *attr,
+                                                char *buf)
+{
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+
+       return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->device_band_groups);
+}
+
+static DEVICE_ATTR(wusb_device_band_groups, 0600,
+                  cbaf_wusb_device_band_groups_show,
+                  NULL);
+
+static ssize_t cbaf_wusb_device_name_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+
+       return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->device_name);
+}
+static DEVICE_ATTR(wusb_device_name, 0600, cbaf_wusb_device_name_show, NULL);
+
+static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = {
+       .AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId,
+       .AssociationTypeId        = cpu_to_le16(AR_TYPE_WUSB),
+       .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
+       .AssociationSubTypeId     = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE),
+       .Length_hdr               = WUSB_AR_Length,
+       .Length         = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)),
+       .ConnectionContext_hdr    = WUSB_AR_ConnectionContext,
+       .BandGroups_hdr           = WUSB_AR_BandGroups,
+};
+
+static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults = {
+       .AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId,
+       .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
+       .Length_hdr               = WUSB_AR_Length,
+       .AssociationStatus_hdr    = WUSB_AR_AssociationStatus,
+};
+
+/*
+ * Send a new CC to the device.
+ */
+static int cbaf_cc_upload(struct cbaf *cbaf)
+{
+       int result;
+       struct device *dev = &cbaf->usb_iface->dev;
+       struct wusb_cbaf_cc_data *ccd;
+
+       ccd =  cbaf->buffer;
+       *ccd = cbaf_cc_data_defaults;
+       ccd->CHID = cbaf->chid;
+       ccd->CDID = cbaf->cdid;
+       ccd->CK = cbaf->ck;
+       ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups);
+
+       dev_dbg(dev, "Trying to upload CC:\n");
+       dev_dbg(dev, "  CHID       %16ph\n", ccd->CHID.data);
+       dev_dbg(dev, "  CDID       %16ph\n", ccd->CDID.data);
+       dev_dbg(dev, "  Bandgroups 0x%04x\n", cbaf->host_band_groups);
+
+       result = usb_control_msg(
+               cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0),
+               CBAF_REQ_SET_ASSOCIATION_RESPONSE,
+               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+               ccd, sizeof(*ccd), USB_CTRL_SET_TIMEOUT);
+
+       return result;
+}
+
+static ssize_t cbaf_wusb_ck_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t size)
+{
+       ssize_t result;
+       struct usb_interface *iface = to_usb_interface(dev);
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+
+       result = sscanf(buf,
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx",
+                       &cbaf->ck.data[0] , &cbaf->ck.data[1],
+                       &cbaf->ck.data[2] , &cbaf->ck.data[3],
+                       &cbaf->ck.data[4] , &cbaf->ck.data[5],
+                       &cbaf->ck.data[6] , &cbaf->ck.data[7],
+                       &cbaf->ck.data[8] , &cbaf->ck.data[9],
+                       &cbaf->ck.data[10], &cbaf->ck.data[11],
+                       &cbaf->ck.data[12], &cbaf->ck.data[13],
+                       &cbaf->ck.data[14], &cbaf->ck.data[15]);
+       if (result != 16)
+               return -EINVAL;
+
+       result = cbaf_cc_upload(cbaf);
+       if (result < 0)
+               return result;
+
+       return size;
+}
+static DEVICE_ATTR(wusb_ck, 0600, NULL, cbaf_wusb_ck_store);
+
+static struct attribute *cbaf_dev_attrs[] = {
+       &dev_attr_wusb_host_name.attr,
+       &dev_attr_wusb_host_band_groups.attr,
+       &dev_attr_wusb_chid.attr,
+       &dev_attr_wusb_cdid.attr,
+       &dev_attr_wusb_device_name.attr,
+       &dev_attr_wusb_device_band_groups.attr,
+       &dev_attr_wusb_ck.attr,
+       NULL,
+};
+
+static const struct attribute_group cbaf_dev_attr_group = {
+       .name = NULL,   /* we want them in the same directory */
+       .attrs = cbaf_dev_attrs,
+};
+
+static int cbaf_probe(struct usb_interface *iface,
+                     const struct usb_device_id *id)
+{
+       struct cbaf *cbaf;
+       struct device *dev = &iface->dev;
+       int result = -ENOMEM;
+
+       cbaf = kzalloc(sizeof(*cbaf), GFP_KERNEL);
+       if (cbaf == NULL)
+               goto error_kzalloc;
+       cbaf->buffer = kmalloc(512, GFP_KERNEL);
+       if (cbaf->buffer == NULL)
+               goto error_kmalloc_buffer;
+
+       cbaf->buffer_size = 512;
+       cbaf->usb_dev = usb_get_dev(interface_to_usbdev(iface));
+       cbaf->usb_iface = usb_get_intf(iface);
+       result = cbaf_check(cbaf);
+       if (result < 0) {
+               dev_err(dev, "This device is not WUSB-CBAF compliant and is not supported yet.\n");
+               goto error_check;
+       }
+
+       result = sysfs_create_group(&dev->kobj, &cbaf_dev_attr_group);
+       if (result < 0) {
+               dev_err(dev, "Can't register sysfs attr group: %d\n", result);
+               goto error_create_group;
+       }
+       usb_set_intfdata(iface, cbaf);
+       return 0;
+
+error_create_group:
+error_check:
+       usb_put_intf(iface);
+       usb_put_dev(cbaf->usb_dev);
+       kfree(cbaf->buffer);
+error_kmalloc_buffer:
+       kfree(cbaf);
+error_kzalloc:
+       return result;
+}
+
+static void cbaf_disconnect(struct usb_interface *iface)
+{
+       struct cbaf *cbaf = usb_get_intfdata(iface);
+       struct device *dev = &iface->dev;
+       sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group);
+       usb_set_intfdata(iface, NULL);
+       usb_put_intf(iface);
+       usb_put_dev(cbaf->usb_dev);
+       kfree(cbaf->buffer);
+       /* paranoia: clean up crypto keys */
+       kzfree(cbaf);
+}
+
+static const struct usb_device_id cbaf_id_table[] = {
+       { USB_INTERFACE_INFO(0xef, 0x03, 0x01), },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, cbaf_id_table);
+
+static struct usb_driver cbaf_driver = {
+       .name =         "wusb-cbaf",
+       .id_table =     cbaf_id_table,
+       .probe =        cbaf_probe,
+       .disconnect =   cbaf_disconnect,
+};
+
+module_usb_driver(cbaf_driver);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless USB Cable Based Association");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/crypto.c b/drivers/staging/wusbcore/crypto.c
new file mode 100644 (file)
index 0000000..d7d55ed
--- /dev/null
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ultra Wide Band
+ * AES-128 CCM Encryption
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * We don't do any encryption here; we use the Linux Kernel's AES-128
+ * crypto modules to construct keys and payload blocks in a way
+ * defined by WUSB1.0[6]. Check the erratas, as typos are are patched
+ * there.
+ *
+ * Thanks a zillion to John Keys for his help and clarifications over
+ * the designed-by-a-committee text.
+ *
+ * So the idea is that there is this basic Pseudo-Random-Function
+ * defined in WUSB1.0[6.5] which is the core of everything. It works
+ * by tweaking some blocks, AES crypting them and then xoring
+ * something else with them (this seems to be called CBC(AES) -- can
+ * you tell I know jack about crypto?). So we just funnel it into the
+ * Linux Crypto API.
+ *
+ * We leave a crypto test module so we can verify that vectors match,
+ * every now and then.
+ *
+ * Block size: 16 bytes -- AES seems to do things in 'block sizes'. I
+ *             am learning a lot...
+ *
+ *             Conveniently, some data structures that need to be
+ *             funneled through AES are...16 bytes in size!
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include <crypto/skcipher.h>
+#include <linux/crypto.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include "../uwb/uwb.h"
+#include "include/wusb.h"
+
+static int debug_crypto_verify;
+
+module_param(debug_crypto_verify, int, 0);
+MODULE_PARM_DESC(debug_crypto_verify, "verify the key generation algorithms");
+
+static void wusb_key_dump(const void *buf, size_t len)
+{
+       print_hex_dump(KERN_ERR, "  ", DUMP_PREFIX_OFFSET, 16, 1,
+                      buf, len, 0);
+}
+
+/*
+ * Block of data, as understood by AES-CCM
+ *
+ * The code assumes this structure is nothing but a 16 byte array
+ * (packed in a struct to avoid common mess ups that I usually do with
+ * arrays and enforcing type checking).
+ */
+struct aes_ccm_block {
+       u8 data[16];
+} __attribute__((packed));
+
+/*
+ * Counter-mode Blocks (WUSB1.0[6.4])
+ *
+ * According to CCM (or so it seems), for the purpose of calculating
+ * the MIC, the message is broken in N counter-mode blocks, B0, B1,
+ * ... BN.
+ *
+ * B0 contains flags, the CCM nonce and l(m).
+ *
+ * B1 contains l(a), the MAC header, the encryption offset and padding.
+ *
+ * If EO is nonzero, additional blocks are built from payload bytes
+ * until EO is exhausted (FIXME: padding to 16 bytes, I guess). The
+ * padding is not xmitted.
+ */
+
+/* WUSB1.0[T6.4] */
+struct aes_ccm_b0 {
+       u8 flags;       /* 0x59, per CCM spec */
+       struct aes_ccm_nonce ccm_nonce;
+       __be16 lm;
+} __attribute__((packed));
+
+/* WUSB1.0[T6.5] */
+struct aes_ccm_b1 {
+       __be16 la;
+       u8 mac_header[10];
+       __le16 eo;
+       u8 security_reserved;   /* This is always zero */
+       u8 padding;             /* 0 */
+} __attribute__((packed));
+
+/*
+ * Encryption Blocks (WUSB1.0[6.4.4])
+ *
+ * CCM uses Ax blocks to generate a keystream with which the MIC and
+ * the message's payload are encoded. A0 always encrypts/decrypts the
+ * MIC. Ax (x>0) are used for the successive payload blocks.
+ *
+ * The x is the counter, and is increased for each block.
+ */
+struct aes_ccm_a {
+       u8 flags;       /* 0x01, per CCM spec */
+       struct aes_ccm_nonce ccm_nonce;
+       __be16 counter; /* Value of x */
+} __attribute__((packed));
+
+/* Scratch space for MAC calculations. */
+struct wusb_mac_scratch {
+       struct aes_ccm_b0 b0;
+       struct aes_ccm_b1 b1;
+       struct aes_ccm_a ax;
+};
+
+/*
+ * CC-MAC function WUSB1.0[6.5]
+ *
+ * Take a data string and produce the encrypted CBC Counter-mode MIC
+ *
+ * Note the names for most function arguments are made to (more or
+ * less) match those used in the pseudo-function definition given in
+ * WUSB1.0[6.5].
+ *
+ * @tfm_cbc: CBC(AES) blkcipher handle (initialized)
+ *
+ * @tfm_aes: AES cipher handle (initialized)
+ *
+ * @mic: buffer for placing the computed MIC (Message Integrity
+ *       Code). This is exactly 8 bytes, and we expect the buffer to
+ *       be at least eight bytes in length.
+ *
+ * @key: 128 bit symmetric key
+ *
+ * @n: CCM nonce
+ *
+ * @a: ASCII string, 14 bytes long (I guess zero padded if needed;
+ *     we use exactly 14 bytes).
+ *
+ * @b: data stream to be processed
+ *
+ * @blen: size of b...
+ *
+ * Still not very clear how this is done, but looks like this: we
+ * create block B0 (as WUSB1.0[6.5] says), then we AES-crypt it with
+ * @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we
+ * take the payload and divide it in blocks (16 bytes), xor them with
+ * the previous crypto result (16 bytes) and crypt it, repeat the next
+ * block with the output of the previous one, rinse wash. So we use
+ * the CBC-MAC(AES) shash, that does precisely that. The IV (Initial
+ * Vector) is 16 bytes and is set to zero, so
+ *
+ * (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and
+ *     using the 14 bytes of @a to fill up
+ *     b1.{mac_header,e0,security_reserved,padding}.
+ *
+ * NOTE: The definition of l(a) in WUSB1.0[6.5] vs the definition of
+ *       l(m) is orthogonal, they bear no relationship, so it is not
+ *       in conflict with the parameter's relation that
+ *       WUSB1.0[6.4.2]) defines.
+ *
+ * NOTE: WUSB1.0[A.1]: Host Nonce is missing a nibble? (1e); fixed in
+ *       first errata released on 2005/07.
+ *
+ * NOTE: we need to clean IV to zero at each invocation to make sure
+ *       we start with a fresh empty Initial Vector, so that the CBC
+ *       works ok.
+ *
+ * NOTE: blen is not aligned to a block size, we'll pad zeros, that's
+ *       what sg[4] is for. Maybe there is a smarter way to do this.
+ */
+static int wusb_ccm_mac(struct crypto_shash *tfm_cbcmac,
+                       struct wusb_mac_scratch *scratch,
+                       void *mic,
+                       const struct aes_ccm_nonce *n,
+                       const struct aes_ccm_label *a, const void *b,
+                       size_t blen)
+{
+       SHASH_DESC_ON_STACK(desc, tfm_cbcmac);
+       u8 iv[AES_BLOCK_SIZE];
+
+       /*
+        * These checks should be compile time optimized out
+        * ensure @a fills b1's mac_header and following fields
+        */
+       BUILD_BUG_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
+       BUILD_BUG_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
+       BUILD_BUG_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
+       BUILD_BUG_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));
+
+       /* Setup B0 */
+       scratch->b0.flags = 0x59;       /* Format B0 */
+       scratch->b0.ccm_nonce = *n;
+       scratch->b0.lm = cpu_to_be16(0);        /* WUSB1.0[6.5] sez l(m) is 0 */
+
+       /* Setup B1
+        *
+        * The WUSB spec is anything but clear! WUSB1.0[6.5]
+        * says that to initialize B1 from A with 'l(a) = blen +
+        * 14'--after clarification, it means to use A's contents
+        * for MAC Header, EO, sec reserved and padding.
+        */
+       scratch->b1.la = cpu_to_be16(blen + 14);
+       memcpy(&scratch->b1.mac_header, a, sizeof(*a));
+
+       desc->tfm = tfm_cbcmac;
+       crypto_shash_init(desc);
+       crypto_shash_update(desc, (u8 *)&scratch->b0, sizeof(scratch->b0) +
+                                                     sizeof(scratch->b1));
+       crypto_shash_finup(desc, b, blen, iv);
+
+       /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5]
+        * The procedure is to AES crypt the A0 block and XOR the MIC
+        * Tag against it; we only do the first 8 bytes and place it
+        * directly in the destination buffer.
+        */
+       scratch->ax.flags = 0x01;               /* as per WUSB 1.0 spec */
+       scratch->ax.ccm_nonce = *n;
+       scratch->ax.counter = 0;
+
+       /* reuse the CBC-MAC transform to perform the single block encryption */
+       crypto_shash_digest(desc, (u8 *)&scratch->ax, sizeof(scratch->ax),
+                           (u8 *)&scratch->ax);
+
+       crypto_xor_cpy(mic, (u8 *)&scratch->ax, iv, 8);
+
+       return 8;
+}
+
+/*
+ * WUSB Pseudo Random Function (WUSB1.0[6.5])
+ *
+ * @b: buffer to the source data; cannot be a global or const local
+ *     (will confuse the scatterlists)
+ */
+ssize_t wusb_prf(void *out, size_t out_size,
+                const u8 key[16], const struct aes_ccm_nonce *_n,
+                const struct aes_ccm_label *a,
+                const void *b, size_t blen, size_t len)
+{
+       ssize_t result, bytes = 0, bitr;
+       struct aes_ccm_nonce n = *_n;
+       struct crypto_shash *tfm_cbcmac;
+       struct wusb_mac_scratch scratch;
+       u64 sfn = 0;
+       __le64 sfn_le;
+
+       tfm_cbcmac = crypto_alloc_shash("cbcmac(aes)", 0, 0);
+       if (IS_ERR(tfm_cbcmac)) {
+               result = PTR_ERR(tfm_cbcmac);
+               printk(KERN_ERR "E: can't load CBCMAC-AES: %d\n", (int)result);
+               goto error_alloc_cbcmac;
+       }
+
+       result = crypto_shash_setkey(tfm_cbcmac, key, AES_BLOCK_SIZE);
+       if (result < 0) {
+               printk(KERN_ERR "E: can't set CBCMAC-AES key: %d\n", (int)result);
+               goto error_setkey_cbcmac;
+       }
+
+       for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
+               sfn_le = cpu_to_le64(sfn++);
+               memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */
+               result = wusb_ccm_mac(tfm_cbcmac, &scratch, out + bytes,
+                                     &n, a, b, blen);
+               if (result < 0)
+                       goto error_ccm_mac;
+               bytes += result;
+       }
+       result = bytes;
+
+error_ccm_mac:
+error_setkey_cbcmac:
+       crypto_free_shash(tfm_cbcmac);
+error_alloc_cbcmac:
+       return result;
+}
+
+/* WUSB1.0[A.2] test vectors */
+static const u8 stv_hsmic_key[16] = {
+       0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d,
+       0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f
+};
+
+static const struct aes_ccm_nonce stv_hsmic_n = {
+       .sfn = { 0 },
+       .tkid = { 0x76, 0x98, 0x01,  },
+       .dest_addr = { .data = { 0xbe, 0x00 } },
+               .src_addr = { .data = { 0x76, 0x98 } },
+};
+
+/*
+ * Out-of-band MIC Generation verification code
+ *
+ */
+static int wusb_oob_mic_verify(void)
+{
+       int result;
+       u8 mic[8];
+       /* WUSB1.0[A.2] test vectors */
+       static const struct usb_handshake stv_hsmic_hs = {
+               .bMessageNumber = 2,
+               .bStatus        = 00,
+               .tTKID          = { 0x76, 0x98, 0x01 },
+               .bReserved      = 00,
+               .CDID           = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+                                   0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+                                   0x3c, 0x3d, 0x3e, 0x3f },
+               .nonce          = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+                                   0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+                                   0x2c, 0x2d, 0x2e, 0x2f },
+               .MIC            = { 0x75, 0x6a, 0x97, 0x51, 0x0c, 0x8c,
+                                   0x14, 0x7b },
+       };
+       size_t hs_size;
+
+       result = wusb_oob_mic(mic, stv_hsmic_key, &stv_hsmic_n, &stv_hsmic_hs);
+       if (result < 0)
+               printk(KERN_ERR "E: WUSB OOB MIC test: failed: %d\n", result);
+       else if (memcmp(stv_hsmic_hs.MIC, mic, sizeof(mic))) {
+               printk(KERN_ERR "E: OOB MIC test: "
+                      "mismatch between MIC result and WUSB1.0[A2]\n");
+               hs_size = sizeof(stv_hsmic_hs) - sizeof(stv_hsmic_hs.MIC);
+               printk(KERN_ERR "E: Handshake2 in: (%zu bytes)\n", hs_size);
+               wusb_key_dump(&stv_hsmic_hs, hs_size);
+               printk(KERN_ERR "E: CCM Nonce in: (%zu bytes)\n",
+                      sizeof(stv_hsmic_n));
+               wusb_key_dump(&stv_hsmic_n, sizeof(stv_hsmic_n));
+               printk(KERN_ERR "E: MIC out:\n");
+               wusb_key_dump(mic, sizeof(mic));
+               printk(KERN_ERR "E: MIC out (from WUSB1.0[A.2]):\n");
+               wusb_key_dump(stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC));
+               result = -EINVAL;
+       } else
+               result = 0;
+       return result;
+}
+
+/*
+ * Test vectors for Key derivation
+ *
+ * These come from WUSB1.0[6.5.1], the vectors in WUSB1.0[A.1]
+ * (errata corrected in 2005/07).
+ */
+static const u8 stv_key_a1[16] __attribute__ ((__aligned__(4))) = {
+       0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87,
+       0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f
+};
+
+static const struct aes_ccm_nonce stv_keydvt_n_a1 = {
+       .sfn = { 0 },
+       .tkid = { 0x76, 0x98, 0x01,  },
+       .dest_addr = { .data = { 0xbe, 0x00 } },
+       .src_addr = { .data = { 0x76, 0x98 } },
+};
+
+static const struct wusb_keydvt_out stv_keydvt_out_a1 = {
+       .kck = {
+               0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d,
+               0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f
+       },
+       .ptk = {
+               0xc8, 0x70, 0x62, 0x82, 0xb6, 0x7c, 0xe9, 0x06,
+               0x7b, 0xc5, 0x25, 0x69, 0xf2, 0x36, 0x61, 0x2d
+       }
+};
+
+/*
+ * Performa a test to make sure we match the vectors defined in
+ * WUSB1.0[A.1](Errata2006/12)
+ */
+static int wusb_key_derive_verify(void)
+{
+       int result = 0;
+       struct wusb_keydvt_out keydvt_out;
+       /* These come from WUSB1.0[A.1] + 2006/12 errata */
+       static const struct wusb_keydvt_in stv_keydvt_in_a1 = {
+               .hnonce = {
+                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+                       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
+               },
+               .dnonce = {
+                       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+                       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
+               }
+       };
+
+       result = wusb_key_derive(&keydvt_out, stv_key_a1, &stv_keydvt_n_a1,
+                                &stv_keydvt_in_a1);
+       if (result < 0)
+               printk(KERN_ERR "E: WUSB key derivation test: "
+                      "derivation failed: %d\n", result);
+       if (memcmp(&stv_keydvt_out_a1, &keydvt_out, sizeof(keydvt_out))) {
+               printk(KERN_ERR "E: WUSB key derivation test: "
+                      "mismatch between key derivation result "
+                      "and WUSB1.0[A1] Errata 2006/12\n");
+               printk(KERN_ERR "E: keydvt in: key\n");
+               wusb_key_dump(stv_key_a1, sizeof(stv_key_a1));
+               printk(KERN_ERR "E: keydvt in: nonce\n");
+               wusb_key_dump(&stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1));
+               printk(KERN_ERR "E: keydvt in: hnonce & dnonce\n");
+               wusb_key_dump(&stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1));
+               printk(KERN_ERR "E: keydvt out: KCK\n");
+               wusb_key_dump(&keydvt_out.kck, sizeof(keydvt_out.kck));
+               printk(KERN_ERR "E: keydvt out: PTK\n");
+               wusb_key_dump(&keydvt_out.ptk, sizeof(keydvt_out.ptk));
+               result = -EINVAL;
+       } else
+               result = 0;
+       return result;
+}
+
+/*
+ * Initialize crypto system
+ *
+ * FIXME: we do nothing now, other than verifying. Later on we'll
+ * cache the encryption stuff, so that's why we have a separate init.
+ */
+int wusb_crypto_init(void)
+{
+       int result;
+
+       if (debug_crypto_verify) {
+               result = wusb_key_derive_verify();
+               if (result < 0)
+                       return result;
+               return wusb_oob_mic_verify();
+       }
+       return 0;
+}
+
+void wusb_crypto_exit(void)
+{
+       /* FIXME: free cached crypto transforms */
+}
diff --git a/drivers/staging/wusbcore/dev-sysfs.c b/drivers/staging/wusbcore/dev-sysfs.c
new file mode 100644 (file)
index 0000000..67b0a4c
--- /dev/null
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB devices
+ * sysfs bindings
+ *
+ * Copyright (C) 2007 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Get them out of the way...
+ */
+
+#include <linux/jiffies.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include "wusbhc.h"
+
+static ssize_t wusb_disconnect_store(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t size)
+{
+       struct usb_device *usb_dev;
+       struct wusbhc *wusbhc;
+       unsigned command;
+       u8 port_idx;
+
+       if (sscanf(buf, "%u", &command) != 1)
+               return -EINVAL;
+       if (command == 0)
+               return size;
+       usb_dev = to_usb_device(dev);
+       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+       if (wusbhc == NULL)
+               return -ENODEV;
+
+       mutex_lock(&wusbhc->mutex);
+       port_idx = wusb_port_no_to_idx(usb_dev->portnum);
+       __wusbhc_dev_disable(wusbhc, port_idx);
+       mutex_unlock(&wusbhc->mutex);
+       wusbhc_put(wusbhc);
+       return size;
+}
+static DEVICE_ATTR_WO(wusb_disconnect);
+
+static ssize_t wusb_cdid_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       ssize_t result;
+       struct wusb_dev *wusb_dev;
+
+       wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev));
+       if (wusb_dev == NULL)
+               return -ENODEV;
+       result = sprintf(buf, "%16ph\n", wusb_dev->cdid.data);
+       wusb_dev_put(wusb_dev);
+       return result;
+}
+static DEVICE_ATTR_RO(wusb_cdid);
+
+static ssize_t wusb_ck_store(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t size)
+{
+       int result;
+       struct usb_device *usb_dev;
+       struct wusbhc *wusbhc;
+       struct wusb_ckhdid ck;
+
+       result = sscanf(buf,
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx\n",
+                       &ck.data[0] , &ck.data[1],
+                       &ck.data[2] , &ck.data[3],
+                       &ck.data[4] , &ck.data[5],
+                       &ck.data[6] , &ck.data[7],
+                       &ck.data[8] , &ck.data[9],
+                       &ck.data[10], &ck.data[11],
+                       &ck.data[12], &ck.data[13],
+                       &ck.data[14], &ck.data[15]);
+       if (result != 16)
+               return -EINVAL;
+
+       usb_dev = to_usb_device(dev);
+       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+       if (wusbhc == NULL)
+               return -ENODEV;
+       result = wusb_dev_4way_handshake(wusbhc, usb_dev->wusb_dev, &ck);
+       memzero_explicit(&ck, sizeof(ck));
+       wusbhc_put(wusbhc);
+       return result < 0 ? result : size;
+}
+static DEVICE_ATTR_WO(wusb_ck);
+
+static struct attribute *wusb_dev_attrs[] = {
+               &dev_attr_wusb_disconnect.attr,
+               &dev_attr_wusb_cdid.attr,
+               &dev_attr_wusb_ck.attr,
+               NULL,
+};
+
+static const struct attribute_group wusb_dev_attr_group = {
+       .name = NULL,   /* we want them in the same directory */
+       .attrs = wusb_dev_attrs,
+};
+
+int wusb_dev_sysfs_add(struct wusbhc *wusbhc, struct usb_device *usb_dev,
+                      struct wusb_dev *wusb_dev)
+{
+       int result = sysfs_create_group(&usb_dev->dev.kobj,
+                                       &wusb_dev_attr_group);
+       struct device *dev = &usb_dev->dev;
+       if (result < 0)
+               dev_err(dev, "Cannot register WUSB-dev attributes: %d\n",
+                       result);
+       return result;
+}
+
+void wusb_dev_sysfs_rm(struct wusb_dev *wusb_dev)
+{
+       struct usb_device *usb_dev = wusb_dev->usb_dev;
+       if (usb_dev)
+               sysfs_remove_group(&usb_dev->dev.kobj, &wusb_dev_attr_group);
+}
diff --git a/drivers/staging/wusbcore/devconnect.c b/drivers/staging/wusbcore/devconnect.c
new file mode 100644 (file)
index 0000000..1170f8b
--- /dev/null
@@ -0,0 +1,1085 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
+ * Device Connect handling
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ * FIXME: this file needs to be broken up, it's grown too big
+ *
+ *
+ * WUSB1.0[7.1, 7.5.1, ]
+ *
+ * WUSB device connection is kind of messy. Some background:
+ *
+ *     When a device wants to connect it scans the UWB radio channels
+ *     looking for a WUSB Channel; a WUSB channel is defined by MMCs
+ *     (Micro Managed Commands or something like that) [see
+ *     Design-overview for more on this] .
+ *
+ * So, device scans the radio, finds MMCs and thus a host and checks
+ * when the next DNTS is. It sends a Device Notification Connect
+ * (DN_Connect); the host picks it up (through nep.c and notif.c, ends
+ * up in wusb_devconnect_ack(), which creates a wusb_dev structure in
+ * wusbhc->port[port_number].wusb_dev), assigns an unauth address
+ * to the device (this means from 0x80 to 0xfe) and sends, in the MMC
+ * a Connect Ack Information Element (ConnAck IE).
+ *
+ * So now the device now has a WUSB address. From now on, we use
+ * that to talk to it in the RPipes.
+ *
+ * ASSUMPTIONS:
+ *
+ *  - We use the the as device address the port number where it is
+ *    connected (port 0 doesn't exist). For unauth, it is 128 + that.
+ *
+ * ROADMAP:
+ *
+ *   This file contains the logic for doing that--entry points:
+ *
+ *   wusb_devconnect_ack()      Ack a device until _acked() called.
+ *                              Called by notif.c:wusb_handle_dn_connect()
+ *                              when a DN_Connect is received.
+ *
+ *     wusb_devconnect_acked()  Ack done, release resources.
+ *
+ *   wusb_handle_dn_alive()     Called by notif.c:wusb_handle_dn()
+ *                              for processing a DN_Alive pong from a device.
+ *
+ *   wusb_handle_dn_disconnect()Called by notif.c:wusb_handle_dn() to
+ *                              process a disconnect request from a
+ *                              device.
+ *
+ *   __wusb_dev_disable()       Called by rh.c:wusbhc_rh_clear_port_feat() when
+ *                              disabling a port.
+ *
+ *   wusb_devconnect_create()   Called when creating the host by
+ *                              lc.c:wusbhc_create().
+ *
+ *   wusb_devconnect_destroy()  Cleanup called removing the host. Called
+ *                              by lc.c:wusbhc_destroy().
+ *
+ *   Each Wireless USB host maintains a list of DN_Connect requests
+ *   (actually we maintain a list of pending Connect Acks, the
+ *   wusbhc->ca_list).
+ *
+ * LIFE CYCLE OF port->wusb_dev
+ *
+ *   Before the @wusbhc structure put()s the reference it owns for
+ *   port->wusb_dev [and clean the wusb_dev pointer], it needs to
+ *   lock @wusbhc->mutex.
+ */
+
+#include <linux/jiffies.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/export.h>
+#include "wusbhc.h"
+
+static void wusbhc_devconnect_acked_work(struct work_struct *work);
+
+static void wusb_dev_free(struct wusb_dev *wusb_dev)
+{
+       kfree(wusb_dev);
+}
+
+static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)
+{
+       struct wusb_dev *wusb_dev;
+
+       wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL);
+       if (wusb_dev == NULL)
+               goto err;
+
+       wusb_dev->wusbhc = wusbhc;
+
+       INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work);
+
+       return wusb_dev;
+err:
+       wusb_dev_free(wusb_dev);
+       return NULL;
+}
+
+
+/*
+ * Using the Connect-Ack list, fill out the @wusbhc Connect-Ack WUSB IE
+ * properly so that it can be added to the MMC.
+ *
+ * We just get the @wusbhc->ca_list and fill out the first four ones or
+ * less (per-spec WUSB1.0[7.5, before T7-38). If the ConnectAck WUSB
+ * IE is not allocated, we alloc it.
+ *
+ * @wusbhc->mutex must be taken
+ */
+static void wusbhc_fill_cack_ie(struct wusbhc *wusbhc)
+{
+       unsigned cnt;
+       struct wusb_dev *dev_itr;
+       struct wuie_connect_ack *cack_ie;
+
+       cack_ie = &wusbhc->cack_ie;
+       cnt = 0;
+       list_for_each_entry(dev_itr, &wusbhc->cack_list, cack_node) {
+               cack_ie->blk[cnt].CDID = dev_itr->cdid;
+               cack_ie->blk[cnt].bDeviceAddress = dev_itr->addr;
+               if (++cnt >= WUIE_ELT_MAX)
+                       break;
+       }
+       cack_ie->hdr.bLength = sizeof(cack_ie->hdr)
+               + cnt * sizeof(cack_ie->blk[0]);
+}
+
+/*
+ * Register a new device that wants to connect
+ *
+ * A new device wants to connect, so we add it to the Connect-Ack
+ * list. We give it an address in the unauthorized range (bit 8 set);
+ * user space will have to drive authorization further on.
+ *
+ * @dev_addr: address to use for the device (which is also the port
+ *            number).
+ *
+ * @wusbhc->mutex must be taken
+ */
+static struct wusb_dev *wusbhc_cack_add(struct wusbhc *wusbhc,
+                                       struct wusb_dn_connect *dnc,
+                                       const char *pr_cdid, u8 port_idx)
+{
+       struct device *dev = wusbhc->dev;
+       struct wusb_dev *wusb_dev;
+       int new_connection = wusb_dn_connect_new_connection(dnc);
+       u8 dev_addr;
+       int result;
+
+       /* Is it registered already? */
+       list_for_each_entry(wusb_dev, &wusbhc->cack_list, cack_node)
+               if (!memcmp(&wusb_dev->cdid, &dnc->CDID,
+                           sizeof(wusb_dev->cdid)))
+                       return wusb_dev;
+       /* We don't have it, create an entry, register it */
+       wusb_dev = wusb_dev_alloc(wusbhc);
+       if (wusb_dev == NULL)
+               return NULL;
+       wusb_dev_init(wusb_dev);
+       wusb_dev->cdid = dnc->CDID;
+       wusb_dev->port_idx = port_idx;
+
+       /*
+        * Devices are always available within the cluster reservation
+        * and since the hardware will take the intersection of the
+        * per-device availability and the cluster reservation, the
+        * per-device availability can simply be set to always
+        * available.
+        */
+       bitmap_fill(wusb_dev->availability.bm, UWB_NUM_MAS);
+
+       /* FIXME: handle reconnects instead of assuming connects are
+          always new. */
+       if (1 && new_connection == 0)
+               new_connection = 1;
+       if (new_connection) {
+               dev_addr = (port_idx + 2) | WUSB_DEV_ADDR_UNAUTH;
+
+               dev_info(dev, "Connecting new WUSB device to address %u, "
+                       "port %u\n", dev_addr, port_idx);
+
+               result = wusb_set_dev_addr(wusbhc, wusb_dev, dev_addr);
+               if (result < 0)
+                       return NULL;
+       }
+       wusb_dev->entry_ts = jiffies;
+       list_add_tail(&wusb_dev->cack_node, &wusbhc->cack_list);
+       wusbhc->cack_count++;
+       wusbhc_fill_cack_ie(wusbhc);
+
+       return wusb_dev;
+}
+
+/*
+ * Remove a Connect-Ack context entry from the HCs view
+ *
+ * @wusbhc->mutex must be taken
+ */
+static void wusbhc_cack_rm(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+       list_del_init(&wusb_dev->cack_node);
+       wusbhc->cack_count--;
+       wusbhc_fill_cack_ie(wusbhc);
+}
+
+/*
+ * @wusbhc->mutex must be taken */
+static
+void wusbhc_devconnect_acked(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+       wusbhc_cack_rm(wusbhc, wusb_dev);
+       if (wusbhc->cack_count)
+               wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr);
+       else
+               wusbhc_mmcie_rm(wusbhc, &wusbhc->cack_ie.hdr);
+}
+
+static void wusbhc_devconnect_acked_work(struct work_struct *work)
+{
+       struct wusb_dev *wusb_dev = container_of(work, struct wusb_dev,
+                                                devconnect_acked_work);
+       struct wusbhc *wusbhc = wusb_dev->wusbhc;
+
+       mutex_lock(&wusbhc->mutex);
+       wusbhc_devconnect_acked(wusbhc, wusb_dev);
+       mutex_unlock(&wusbhc->mutex);
+
+       wusb_dev_put(wusb_dev);
+}
+
+/*
+ * Ack a device for connection
+ *
+ * FIXME: docs
+ *
+ * @pr_cdid:   Printable CDID...hex Use @dnc->cdid for the real deal.
+ *
+ * So we get the connect ack IE (may have been allocated already),
+ * find an empty connect block, an empty virtual port, create an
+ * address with it (see below), make it an unauth addr [bit 7 set] and
+ * set the MMC.
+ *
+ * Addresses: because WUSB hosts have no downstream hubs, we can do a
+ *            1:1 mapping between 'port number' and device
+ *            address. This simplifies many things, as during this
+ *            initial connect phase the USB stack has no knowledge of
+ *            the device and hasn't assigned an address yet--we know
+ *            USB's choose_address() will use the same heuristics we
+ *            use here, so we can assume which address will be assigned.
+ *
+ *            USB stack always assigns address 1 to the root hub, so
+ *            to the port number we add 2 (thus virtual port #0 is
+ *            addr #2).
+ *
+ * @wusbhc shall be referenced
+ */
+static
+void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc,
+                          const char *pr_cdid)
+{
+       int result;
+       struct device *dev = wusbhc->dev;
+       struct wusb_dev *wusb_dev;
+       struct wusb_port *port;
+       unsigned idx;
+
+       mutex_lock(&wusbhc->mutex);
+
+       /* Check we are not handling it already */
+       for (idx = 0; idx < wusbhc->ports_max; idx++) {
+               port = wusb_port_by_idx(wusbhc, idx);
+               if (port->wusb_dev
+                   && memcmp(&dnc->CDID, &port->wusb_dev->cdid, sizeof(dnc->CDID)) == 0)
+                       goto error_unlock;
+       }
+       /* Look up those fake ports we have for a free one */
+       for (idx = 0; idx < wusbhc->ports_max; idx++) {
+               port = wusb_port_by_idx(wusbhc, idx);
+               if ((port->status & USB_PORT_STAT_POWER)
+                   && !(port->status & USB_PORT_STAT_CONNECTION))
+                       break;
+       }
+       if (idx >= wusbhc->ports_max) {
+               dev_err(dev, "Host controller can't connect more devices "
+                       "(%u already connected); device %s rejected\n",
+                       wusbhc->ports_max, pr_cdid);
+               /* NOTE: we could send a WUIE_Disconnect here, but we haven't
+                *       event acked, so the device will eventually timeout the
+                *       connection, right? */
+               goto error_unlock;
+       }
+
+       /* Make sure we are using no crypto on that "virtual port" */
+       wusbhc->set_ptk(wusbhc, idx, 0, NULL, 0);
+
+       /* Grab a filled in Connect-Ack context, fill out the
+        * Connect-Ack Wireless USB IE, set the MMC */
+       wusb_dev = wusbhc_cack_add(wusbhc, dnc, pr_cdid, idx);
+       if (wusb_dev == NULL)
+               goto error_unlock;
+       result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr);
+       if (result < 0)
+               goto error_unlock;
+       /* Give the device at least 2ms (WUSB1.0[7.5.1p3]), let's do
+        * three for a good measure */
+       msleep(3);
+       port->wusb_dev = wusb_dev;
+       port->status |= USB_PORT_STAT_CONNECTION;
+       port->change |= USB_PORT_STAT_C_CONNECTION;
+       /* Now the port status changed to connected; hub_wq will
+        * pick the change up and try to reset the port to bring it to
+        * the enabled state--so this process returns up to the stack
+        * and it calls back into wusbhc_rh_port_reset().
+        */
+error_unlock:
+       mutex_unlock(&wusbhc->mutex);
+       return;
+
+}
+
+/*
+ * Disconnect a Wireless USB device from its fake port
+ *
+ * Marks the port as disconnected so that hub_wq can pick up the change
+ * and drops our knowledge about the device.
+ *
+ * Assumes there is a device connected
+ *
+ * @port_index: zero based port number
+ *
+ * NOTE: @wusbhc->mutex is locked
+ *
+ * WARNING: From here it is not very safe to access anything hanging off
+ *         wusb_dev
+ */
+static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc,
+                                   struct wusb_port *port)
+{
+       struct wusb_dev *wusb_dev = port->wusb_dev;
+
+       port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE
+                         | USB_PORT_STAT_SUSPEND | USB_PORT_STAT_RESET
+                         | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
+       port->change |= USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE;
+       if (wusb_dev) {
+               dev_dbg(wusbhc->dev, "disconnecting device from port %d\n", wusb_dev->port_idx);
+               if (!list_empty(&wusb_dev->cack_node))
+                       list_del_init(&wusb_dev->cack_node);
+               /* For the one in cack_add() */
+               wusb_dev_put(wusb_dev);
+       }
+       port->wusb_dev = NULL;
+
+       /* After a device disconnects, change the GTK (see [WUSB]
+        * section 6.2.11.2). */
+       if (wusbhc->active)
+               wusbhc_gtk_rekey(wusbhc);
+
+       /* The Wireless USB part has forgotten about the device already; now
+        * hub_wq's timer will pick up the disconnection and remove the USB
+        * device from the system
+        */
+}
+
+/*
+ * Refresh the list of keep alives to emit in the MMC
+ *
+ * We only publish the first four devices that have a coming timeout
+ * condition. Then when we are done processing those, we go for the
+ * next ones. We ignore the ones that have timed out already (they'll
+ * be purged).
+ *
+ * This might cause the first devices to timeout the last devices in
+ * the port array...FIXME: come up with a better algorithm?
+ *
+ * Note we can't do much about MMC's ops errors; we hope next refresh
+ * will kind of handle it.
+ *
+ * NOTE: @wusbhc->mutex is locked
+ */
+static void __wusbhc_keep_alive(struct wusbhc *wusbhc)
+{
+       struct device *dev = wusbhc->dev;
+       unsigned cnt;
+       struct wusb_dev *wusb_dev;
+       struct wusb_port *wusb_port;
+       struct wuie_keep_alive *ie = &wusbhc->keep_alive_ie;
+       unsigned keep_alives, old_keep_alives;
+
+       old_keep_alives = ie->hdr.bLength - sizeof(ie->hdr);
+       keep_alives = 0;
+       for (cnt = 0;
+            keep_alives < WUIE_ELT_MAX && cnt < wusbhc->ports_max;
+            cnt++) {
+               unsigned tt = msecs_to_jiffies(wusbhc->trust_timeout);
+
+               wusb_port = wusb_port_by_idx(wusbhc, cnt);
+               wusb_dev = wusb_port->wusb_dev;
+
+               if (wusb_dev == NULL)
+                       continue;
+               if (wusb_dev->usb_dev == NULL)
+                       continue;
+
+               if (time_after(jiffies, wusb_dev->entry_ts + tt)) {
+                       dev_err(dev, "KEEPALIVE: device %u timed out\n",
+                               wusb_dev->addr);
+                       __wusbhc_dev_disconnect(wusbhc, wusb_port);
+               } else if (time_after(jiffies, wusb_dev->entry_ts + tt/3)) {
+                       /* Approaching timeout cut off, need to refresh */
+                       ie->bDeviceAddress[keep_alives++] = wusb_dev->addr;
+               }
+       }
+       if (keep_alives & 0x1)  /* pad to even number ([WUSB] section 7.5.9) */
+               ie->bDeviceAddress[keep_alives++] = 0x7f;
+       ie->hdr.bLength = sizeof(ie->hdr) +
+               keep_alives*sizeof(ie->bDeviceAddress[0]);
+       if (keep_alives > 0)
+               wusbhc_mmcie_set(wusbhc, 10, 5, &ie->hdr);
+       else if (old_keep_alives != 0)
+               wusbhc_mmcie_rm(wusbhc, &ie->hdr);
+}
+
+/*
+ * Do a run through all devices checking for timeouts
+ */
+static void wusbhc_keep_alive_run(struct work_struct *ws)
+{
+       struct delayed_work *dw = to_delayed_work(ws);
+       struct wusbhc *wusbhc = container_of(dw, struct wusbhc, keep_alive_timer);
+
+       mutex_lock(&wusbhc->mutex);
+       __wusbhc_keep_alive(wusbhc);
+       mutex_unlock(&wusbhc->mutex);
+
+       queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
+                          msecs_to_jiffies(wusbhc->trust_timeout / 2));
+}
+
+/*
+ * Find the wusb_dev from its device address.
+ *
+ * The device can be found directly from the address (see
+ * wusb_cack_add() for where the device address is set to port_idx
+ * +2), except when the address is zero.
+ */
+static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)
+{
+       int p;
+
+       if (addr == 0xff) /* unconnected */
+               return NULL;
+
+       if (addr > 0) {
+               int port = (addr & ~0x80) - 2;
+               if (port < 0 || port >= wusbhc->ports_max)
+                       return NULL;
+               return wusb_port_by_idx(wusbhc, port)->wusb_dev;
+       }
+
+       /* Look for the device with address 0. */
+       for (p = 0; p < wusbhc->ports_max; p++) {
+               struct wusb_dev *wusb_dev = wusb_port_by_idx(wusbhc, p)->wusb_dev;
+               if (wusb_dev && wusb_dev->addr == addr)
+                       return wusb_dev;
+       }
+       return NULL;
+}
+
+/*
+ * Handle a DN_Alive notification (WUSB1.0[7.6.1])
+ *
+ * This just updates the device activity timestamp and then refreshes
+ * the keep alive IE.
+ *
+ * @wusbhc shall be referenced and unlocked
+ */
+static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, u8 srcaddr)
+{
+       struct wusb_dev *wusb_dev;
+
+       mutex_lock(&wusbhc->mutex);
+       wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
+       if (wusb_dev == NULL) {
+               dev_dbg(wusbhc->dev, "ignoring DN_Alive from unconnected device %02x\n",
+                       srcaddr);
+       } else {
+               wusb_dev->entry_ts = jiffies;
+               __wusbhc_keep_alive(wusbhc);
+       }
+       mutex_unlock(&wusbhc->mutex);
+}
+
+/*
+ * Handle a DN_Connect notification (WUSB1.0[7.6.1])
+ *
+ * @wusbhc
+ * @pkt_hdr
+ * @size:    Size of the buffer where the notification resides; if the
+ *           notification data suggests there should be more data than
+ *           available, an error will be signaled and the whole buffer
+ *           consumed.
+ *
+ * @wusbhc->mutex shall be held
+ */
+static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,
+                                    struct wusb_dn_hdr *dn_hdr,
+                                    size_t size)
+{
+       struct device *dev = wusbhc->dev;
+       struct wusb_dn_connect *dnc;
+       char pr_cdid[WUSB_CKHDID_STRSIZE];
+       static const char *beacon_behaviour[] = {
+               "reserved",
+               "self-beacon",
+               "directed-beacon",
+               "no-beacon"
+       };
+
+       if (size < sizeof(*dnc)) {
+               dev_err(dev, "DN CONNECT: short notification (%zu < %zu)\n",
+                       size, sizeof(*dnc));
+               return;
+       }
+
+       dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr);
+       sprintf(pr_cdid, "%16ph", dnc->CDID.data);
+       dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n",
+                pr_cdid,
+                wusb_dn_connect_prev_dev_addr(dnc),
+                beacon_behaviour[wusb_dn_connect_beacon_behavior(dnc)],
+                wusb_dn_connect_new_connection(dnc) ? "connect" : "reconnect");
+       /* ACK the connect */
+       wusbhc_devconnect_ack(wusbhc, dnc, pr_cdid);
+}
+
+/*
+ * Handle a DN_Disconnect notification (WUSB1.0[7.6.1])
+ *
+ * Device is going down -- do the disconnect.
+ *
+ * @wusbhc shall be referenced and unlocked
+ */
+static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, u8 srcaddr)
+{
+       struct device *dev = wusbhc->dev;
+       struct wusb_dev *wusb_dev;
+
+       mutex_lock(&wusbhc->mutex);
+       wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
+       if (wusb_dev == NULL) {
+               dev_dbg(dev, "ignoring DN DISCONNECT from unconnected device %02x\n",
+                       srcaddr);
+       } else {
+               dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n",
+                       wusb_dev->addr);
+               __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc,
+                       wusb_dev->port_idx));
+       }
+       mutex_unlock(&wusbhc->mutex);
+}
+
+/*
+ * Handle a Device Notification coming a host
+ *
+ * The Device Notification comes from a host (HWA, DWA or WHCI)
+ * wrapped in a set of headers. Somebody else has peeled off those
+ * headers for us and we just get one Device Notifications.
+ *
+ * Invalid DNs (e.g., too short) are discarded.
+ *
+ * @wusbhc shall be referenced
+ *
+ * FIXMES:
+ *  - implement priorities as in WUSB1.0[Table 7-55]?
+ */
+void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr,
+                     struct wusb_dn_hdr *dn_hdr, size_t size)
+{
+       struct device *dev = wusbhc->dev;
+
+       if (size < sizeof(struct wusb_dn_hdr)) {
+               dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
+                       (int)size, (int)sizeof(struct wusb_dn_hdr));
+               return;
+       }
+       switch (dn_hdr->bType) {
+       case WUSB_DN_CONNECT:
+               wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
+               break;
+       case WUSB_DN_ALIVE:
+               wusbhc_handle_dn_alive(wusbhc, srcaddr);
+               break;
+       case WUSB_DN_DISCONNECT:
+               wusbhc_handle_dn_disconnect(wusbhc, srcaddr);
+               break;
+       case WUSB_DN_MASAVAILCHANGED:
+       case WUSB_DN_RWAKE:
+       case WUSB_DN_SLEEP:
+               /* FIXME: handle these DNs. */
+               break;
+       case WUSB_DN_EPRDY:
+               /* The hardware handles these. */
+               break;
+       default:
+               dev_warn(dev, "unknown DN %u (%d octets) from %u\n",
+                        dn_hdr->bType, (int)size, srcaddr);
+       }
+}
+EXPORT_SYMBOL_GPL(wusbhc_handle_dn);
+
+/*
+ * Disconnect a WUSB device from a the cluster
+ *
+ * @wusbhc
+ * @port     Fake port where the device is (wusbhc index, not USB port number).
+ *
+ * In Wireless USB, a disconnect is basically telling the device he is
+ * being disconnected and forgetting about him.
+ *
+ * We send the device a Device Disconnect IE (WUSB1.0[7.5.11]) for 100
+ * ms and then keep going.
+ *
+ * We don't do much in case of error; we always pretend we disabled
+ * the port and disconnected the device. If physically the request
+ * didn't get there (many things can fail in the way there), the stack
+ * will reject the device's communication attempts.
+ *
+ * @wusbhc should be refcounted and locked
+ */
+void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port_idx)
+{
+       int result;
+       struct device *dev = wusbhc->dev;
+       struct wusb_dev *wusb_dev;
+       struct wuie_disconnect *ie;
+
+       wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
+       if (wusb_dev == NULL) {
+               /* reset no device? ignore */
+               dev_dbg(dev, "DISCONNECT: no device at port %u, ignoring\n",
+                       port_idx);
+               return;
+       }
+       __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
+
+       ie = kzalloc(sizeof(*ie), GFP_KERNEL);
+       if (ie == NULL)
+               return;
+       ie->hdr.bLength = sizeof(*ie);
+       ie->hdr.bIEIdentifier = WUIE_ID_DEVICE_DISCONNECT;
+       ie->bDeviceAddress = wusb_dev->addr;
+       result = wusbhc_mmcie_set(wusbhc, 0, 0, &ie->hdr);
+       if (result < 0)
+               dev_err(dev, "DISCONNECT: can't set MMC: %d\n", result);
+       else {
+               /* At least 6 MMCs, assuming at least 1 MMC per zone. */
+               msleep(7*4);
+               wusbhc_mmcie_rm(wusbhc, &ie->hdr);
+       }
+       kfree(ie);
+}
+
+/*
+ * Walk over the BOS descriptor, verify and grok it
+ *
+ * @usb_dev: referenced
+ * @wusb_dev: referenced and unlocked
+ *
+ * The BOS descriptor is defined at WUSB1.0[7.4.1], and it defines a
+ * "flexible" way to wrap all kinds of descriptors inside an standard
+ * descriptor (wonder why they didn't use normal descriptors,
+ * btw). Not like they lack code.
+ *
+ * At the end we go to look for the WUSB Device Capabilities
+ * (WUSB1.0[7.4.1.1]) that is wrapped in a device capability descriptor
+ * that is part of the BOS descriptor set. That tells us what does the
+ * device support (dual role, beacon type, UWB PHY rates).
+ */
+static int wusb_dev_bos_grok(struct usb_device *usb_dev,
+                            struct wusb_dev *wusb_dev,
+                            struct usb_bos_descriptor *bos, size_t desc_size)
+{
+       ssize_t result;
+       struct device *dev = &usb_dev->dev;
+       void *itr, *top;
+
+       /* Walk over BOS capabilities, verify them */
+       itr = (void *)bos + sizeof(*bos);
+       top = itr + desc_size - sizeof(*bos);
+       while (itr < top) {
+               struct usb_dev_cap_header *cap_hdr = itr;
+               size_t cap_size;
+               u8 cap_type;
+               if (top - itr < sizeof(*cap_hdr)) {
+                       dev_err(dev, "Device BUG? premature end of BOS header "
+                               "data [offset 0x%02x]: only %zu bytes left\n",
+                               (int)(itr - (void *)bos), top - itr);
+                       result = -ENOSPC;
+                       goto error_bad_cap;
+               }
+               cap_size = cap_hdr->bLength;
+               cap_type = cap_hdr->bDevCapabilityType;
+               if (cap_size == 0)
+                       break;
+               if (cap_size > top - itr) {
+                       dev_err(dev, "Device BUG? premature end of BOS data "
+                               "[offset 0x%02x cap %02x %zu bytes]: "
+                               "only %zu bytes left\n",
+                               (int)(itr - (void *)bos),
+                               cap_type, cap_size, top - itr);
+                       result = -EBADF;
+                       goto error_bad_cap;
+               }
+               switch (cap_type) {
+               case USB_CAP_TYPE_WIRELESS_USB:
+                       if (cap_size != sizeof(*wusb_dev->wusb_cap_descr))
+                               dev_err(dev, "Device BUG? WUSB Capability "
+                                       "descriptor is %zu bytes vs %zu "
+                                       "needed\n", cap_size,
+                                       sizeof(*wusb_dev->wusb_cap_descr));
+                       else
+                               wusb_dev->wusb_cap_descr = itr;
+                       break;
+               default:
+                       dev_err(dev, "BUG? Unknown BOS capability 0x%02x "
+                               "(%zu bytes) at offset 0x%02x\n", cap_type,
+                               cap_size, (int)(itr - (void *)bos));
+               }
+               itr += cap_size;
+       }
+       result = 0;
+error_bad_cap:
+       return result;
+}
+
+/*
+ * Add information from the BOS descriptors to the device
+ *
+ * @usb_dev: referenced
+ * @wusb_dev: referenced and unlocked
+ *
+ * So what we do is we alloc a space for the BOS descriptor of 64
+ * bytes; read the first four bytes which include the wTotalLength
+ * field (WUSB1.0[T7-26]) and if it fits in those 64 bytes, read the
+ * whole thing. If not we realloc to that size.
+ *
+ * Then we call the groking function, that will fill up
+ * wusb_dev->wusb_cap_descr, which is what we'll need later on.
+ */
+static int wusb_dev_bos_add(struct usb_device *usb_dev,
+                           struct wusb_dev *wusb_dev)
+{
+       ssize_t result;
+       struct device *dev = &usb_dev->dev;
+       struct usb_bos_descriptor *bos;
+       size_t alloc_size = 32, desc_size = 4;
+
+       bos = kmalloc(alloc_size, GFP_KERNEL);
+       if (bos == NULL)
+               return -ENOMEM;
+       result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size);
+       if (result < 4) {
+               dev_err(dev, "Can't get BOS descriptor or too short: %zd\n",
+                       result);
+               goto error_get_descriptor;
+       }
+       desc_size = le16_to_cpu(bos->wTotalLength);
+       if (desc_size >= alloc_size) {
+               kfree(bos);
+               alloc_size = desc_size;
+               bos = kmalloc(alloc_size, GFP_KERNEL);
+               if (bos == NULL)
+                       return -ENOMEM;
+       }
+       result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size);
+       if (result < 0 || result != desc_size) {
+               dev_err(dev, "Can't get  BOS descriptor or too short (need "
+                       "%zu bytes): %zd\n", desc_size, result);
+               goto error_get_descriptor;
+       }
+       if (result < sizeof(*bos)
+           || le16_to_cpu(bos->wTotalLength) != desc_size) {
+               dev_err(dev, "Can't get  BOS descriptor or too short (need "
+                       "%zu bytes): %zd\n", desc_size, result);
+               goto error_get_descriptor;
+       }
+
+       result = wusb_dev_bos_grok(usb_dev, wusb_dev, bos, result);
+       if (result < 0)
+               goto error_bad_bos;
+       wusb_dev->bos = bos;
+       return 0;
+
+error_bad_bos:
+error_get_descriptor:
+       kfree(bos);
+       wusb_dev->wusb_cap_descr = NULL;
+       return result;
+}
+
+static void wusb_dev_bos_rm(struct wusb_dev *wusb_dev)
+{
+       kfree(wusb_dev->bos);
+       wusb_dev->wusb_cap_descr = NULL;
+};
+
+/*
+ * USB stack's device addition Notifier Callback
+ *
+ * Called from drivers/usb/core/hub.c when a new device is added; we
+ * use this hook to perform certain WUSB specific setup work on the
+ * new device. As well, it is the first time we can connect the
+ * wusb_dev and the usb_dev. So we note it down in wusb_dev and take a
+ * reference that we'll drop.
+ *
+ * First we need to determine if the device is a WUSB device (else we
+ * ignore it). For that we use the speed setting (USB_SPEED_WIRELESS)
+ * [FIXME: maybe we'd need something more definitive]. If so, we track
+ * it's usb_busd and from there, the WUSB HC.
+ *
+ * Because all WUSB HCs are contained in a 'struct wusbhc', voila, we
+ * get the wusbhc for the device.
+ *
+ * We have a reference on @usb_dev (as we are called at the end of its
+ * enumeration).
+ *
+ * NOTE: @usb_dev locked
+ */
+static void wusb_dev_add_ncb(struct usb_device *usb_dev)
+{
+       int result = 0;
+       struct wusb_dev *wusb_dev;
+       struct wusbhc *wusbhc;
+       struct device *dev = &usb_dev->dev;
+       u8 port_idx;
+
+       if (usb_dev->wusb == 0 || usb_dev->devnum == 1)
+               return;         /* skip non wusb and wusb RHs */
+
+       usb_set_device_state(usb_dev, USB_STATE_UNAUTHENTICATED);
+
+       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+       if (wusbhc == NULL)
+               goto error_nodev;
+       mutex_lock(&wusbhc->mutex);
+       wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev);
+       port_idx = wusb_port_no_to_idx(usb_dev->portnum);
+       mutex_unlock(&wusbhc->mutex);
+       if (wusb_dev == NULL)
+               goto error_nodev;
+       wusb_dev->usb_dev = usb_get_dev(usb_dev);
+       usb_dev->wusb_dev = wusb_dev_get(wusb_dev);
+       result = wusb_dev_sec_add(wusbhc, usb_dev, wusb_dev);
+       if (result < 0) {
+               dev_err(dev, "Cannot enable security: %d\n", result);
+               goto error_sec_add;
+       }
+       /* Now query the device for it's BOS and attach it to wusb_dev */
+       result = wusb_dev_bos_add(usb_dev, wusb_dev);
+       if (result < 0) {
+               dev_err(dev, "Cannot get BOS descriptors: %d\n", result);
+               goto error_bos_add;
+       }
+       result = wusb_dev_sysfs_add(wusbhc, usb_dev, wusb_dev);
+       if (result < 0)
+               goto error_add_sysfs;
+out:
+       wusb_dev_put(wusb_dev);
+       wusbhc_put(wusbhc);
+error_nodev:
+       return;
+
+error_add_sysfs:
+       wusb_dev_bos_rm(wusb_dev);
+error_bos_add:
+       wusb_dev_sec_rm(wusb_dev);
+error_sec_add:
+       mutex_lock(&wusbhc->mutex);
+       __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
+       mutex_unlock(&wusbhc->mutex);
+       goto out;
+}
+
+/*
+ * Undo all the steps done at connection by the notifier callback
+ *
+ * NOTE: @usb_dev locked
+ */
+static void wusb_dev_rm_ncb(struct usb_device *usb_dev)
+{
+       struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
+
+       if (usb_dev->wusb == 0 || usb_dev->devnum == 1)
+               return;         /* skip non wusb and wusb RHs */
+
+       wusb_dev_sysfs_rm(wusb_dev);
+       wusb_dev_bos_rm(wusb_dev);
+       wusb_dev_sec_rm(wusb_dev);
+       wusb_dev->usb_dev = NULL;
+       usb_dev->wusb_dev = NULL;
+       wusb_dev_put(wusb_dev);
+       usb_put_dev(usb_dev);
+}
+
+/*
+ * Handle notifications from the USB stack (notifier call back)
+ *
+ * This is called when the USB stack does a
+ * usb_{bus,device}_{add,remove}() so we can do WUSB specific
+ * handling. It is called with [for the case of
+ * USB_DEVICE_{ADD,REMOVE} with the usb_dev locked.
+ */
+int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,
+                void *priv)
+{
+       int result = NOTIFY_OK;
+
+       switch (val) {
+       case USB_DEVICE_ADD:
+               wusb_dev_add_ncb(priv);
+               break;
+       case USB_DEVICE_REMOVE:
+               wusb_dev_rm_ncb(priv);
+               break;
+       case USB_BUS_ADD:
+               /* ignore (for now) */
+       case USB_BUS_REMOVE:
+               break;
+       default:
+               WARN_ON(1);
+               result = NOTIFY_BAD;
+       }
+       return result;
+}
+
+/*
+ * Return a referenced wusb_dev given a @wusbhc and @usb_dev
+ */
+struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *wusbhc,
+                                          struct usb_device *usb_dev)
+{
+       struct wusb_dev *wusb_dev;
+       u8 port_idx;
+
+       port_idx = wusb_port_no_to_idx(usb_dev->portnum);
+       BUG_ON(port_idx > wusbhc->ports_max);
+       wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
+       if (wusb_dev != NULL)           /* ops, device is gone */
+               wusb_dev_get(wusb_dev);
+       return wusb_dev;
+}
+EXPORT_SYMBOL_GPL(__wusb_dev_get_by_usb_dev);
+
+void wusb_dev_destroy(struct kref *_wusb_dev)
+{
+       struct wusb_dev *wusb_dev = container_of(_wusb_dev, struct wusb_dev, refcnt);
+
+       list_del_init(&wusb_dev->cack_node);
+       wusb_dev_free(wusb_dev);
+}
+EXPORT_SYMBOL_GPL(wusb_dev_destroy);
+
+/*
+ * Create all the device connect handling infrastructure
+ *
+ * This is basically the device info array, Connect Acknowledgement
+ * (cack) lists, keep-alive timers (and delayed work thread).
+ */
+int wusbhc_devconnect_create(struct wusbhc *wusbhc)
+{
+       wusbhc->keep_alive_ie.hdr.bIEIdentifier = WUIE_ID_KEEP_ALIVE;
+       wusbhc->keep_alive_ie.hdr.bLength = sizeof(wusbhc->keep_alive_ie.hdr);
+       INIT_DELAYED_WORK(&wusbhc->keep_alive_timer, wusbhc_keep_alive_run);
+
+       wusbhc->cack_ie.hdr.bIEIdentifier = WUIE_ID_CONNECTACK;
+       wusbhc->cack_ie.hdr.bLength = sizeof(wusbhc->cack_ie.hdr);
+       INIT_LIST_HEAD(&wusbhc->cack_list);
+
+       return 0;
+}
+
+/*
+ * Release all resources taken by the devconnect stuff
+ */
+void wusbhc_devconnect_destroy(struct wusbhc *wusbhc)
+{
+       /* no op */
+}
+
+/*
+ * wusbhc_devconnect_start - start accepting device connections
+ * @wusbhc: the WUSB HC
+ *
+ * Sets the Host Info IE to accept all new connections.
+ *
+ * FIXME: This also enables the keep alives but this is not necessary
+ * until there are connected and authenticated devices.
+ */
+int wusbhc_devconnect_start(struct wusbhc *wusbhc)
+{
+       struct device *dev = wusbhc->dev;
+       struct wuie_host_info *hi;
+       int result;
+
+       hi = kzalloc(sizeof(*hi), GFP_KERNEL);
+       if (hi == NULL)
+               return -ENOMEM;
+
+       hi->hdr.bLength       = sizeof(*hi);
+       hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO;
+       hi->attributes        = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL);
+       hi->CHID              = wusbhc->chid;
+       result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr);
+       if (result < 0) {
+               dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result);
+               goto error_mmcie_set;
+       }
+       wusbhc->wuie_host_info = hi;
+
+       queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
+                          msecs_to_jiffies(wusbhc->trust_timeout / 2));
+
+       return 0;
+
+error_mmcie_set:
+       kfree(hi);
+       return result;
+}
+
+/*
+ * wusbhc_devconnect_stop - stop managing connected devices
+ * @wusbhc: the WUSB HC
+ *
+ * Disconnects any devices still connected, stops the keep alives and
+ * removes the Host Info IE.
+ */
+void wusbhc_devconnect_stop(struct wusbhc *wusbhc)
+{
+       int i;
+
+       mutex_lock(&wusbhc->mutex);
+       for (i = 0; i < wusbhc->ports_max; i++) {
+               if (wusbhc->port[i].wusb_dev)
+                       __wusbhc_dev_disconnect(wusbhc, &wusbhc->port[i]);
+       }
+       mutex_unlock(&wusbhc->mutex);
+
+       cancel_delayed_work_sync(&wusbhc->keep_alive_timer);
+       wusbhc_mmcie_rm(wusbhc, &wusbhc->wuie_host_info->hdr);
+       kfree(wusbhc->wuie_host_info);
+       wusbhc->wuie_host_info = NULL;
+}
+
+/*
+ * wusb_set_dev_addr - set the WUSB device address used by the host
+ * @wusbhc: the WUSB HC the device is connect to
+ * @wusb_dev: the WUSB device
+ * @addr: new device address
+ */
+int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, u8 addr)
+{
+       int result;
+
+       wusb_dev->addr = addr;
+       result = wusbhc->dev_info_set(wusbhc, wusb_dev);
+       if (result < 0)
+               dev_err(wusbhc->dev, "device %d: failed to set device "
+                       "address\n", wusb_dev->port_idx);
+       else
+               dev_info(wusbhc->dev, "device %d: %s addr %u\n",
+                        wusb_dev->port_idx,
+                        (addr & WUSB_DEV_ADDR_UNAUTH) ? "unauth" : "auth",
+                        wusb_dev->addr);
+
+       return result;
+}
diff --git a/drivers/staging/wusbcore/host/Kconfig b/drivers/staging/wusbcore/host/Kconfig
new file mode 100644 (file)
index 0000000..9a73f93
--- /dev/null
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+
+config USB_WHCI_HCD
+       tristate "Wireless USB Host Controller Interface (WHCI) driver"
+       depends on USB_PCI && USB && UWB
+       select USB_WUSB
+       select UWB_WHCI
+       help
+         A driver for PCI-based Wireless USB Host Controllers that are
+         compliant with the WHCI specification.
+
+         To compile this driver a module, choose M here: the module
+         will be called "whci-hcd".
+
+config USB_HWA_HCD
+       tristate "Host Wire Adapter (HWA) driver"
+       depends on USB && UWB
+       select USB_WUSB
+       select UWB_HWA
+       help
+         This driver enables you to connect Wireless USB devices to
+         your system using a Host Wire Adaptor USB dongle. This is an
+         UWB Radio Controller and WUSB Host Controller connected to
+         your machine via USB (specified in WUSB1.0).
+
+         To compile this driver a module, choose M here: the module
+         will be called "hwa-hc".
+
diff --git a/drivers/staging/wusbcore/host/Makefile b/drivers/staging/wusbcore/host/Makefile
new file mode 100644 (file)
index 0000000..d65ee8a
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_USB_WHCI_HCD)     += whci/
+obj-$(CONFIG_USB_HWA_HCD)      += hwa-hc.o
diff --git a/drivers/staging/wusbcore/host/hwa-hc.c b/drivers/staging/wusbcore/host/hwa-hc.c
new file mode 100644 (file)
index 0000000..8d959e9
--- /dev/null
@@ -0,0 +1,875 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Host Wire Adapter:
+ * Driver glue, HWA-specific functions, bridges to WAHC and WUSBHC
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * The HWA driver is a simple layer that forwards requests to the WAHC
+ * (Wire Adater Host Controller) or WUSBHC (Wireless USB Host
+ * Controller) layers.
+ *
+ * Host Wire Adapter is the 'WUSB 1.0 standard' name for Wireless-USB
+ * Host Controller that is connected to your system via USB (a USB
+ * dongle that implements a USB host...). There is also a Device Wired
+ * Adaptor, DWA (Wireless USB hub) that uses the same mechanism for
+ * transferring data (it is after all a USB host connected via
+ * Wireless USB), we have a common layer called Wire Adapter Host
+ * Controller that does all the hard work. The WUSBHC (Wireless USB
+ * Host Controller) is the part common to WUSB Host Controllers, the
+ * HWA and the PCI-based one, that is implemented following the WHCI
+ * spec. All these layers are implemented in ../wusbcore.
+ *
+ * The main functions are hwahc_op_urb_{en,de}queue(), that pass the
+ * job of converting a URB to a Wire Adapter
+ *
+ * Entry points:
+ *
+ *   hwahc_driver_*()   Driver initialization, registration and
+ *                      teardown.
+ *
+ *   hwahc_probe()     New device came up, create an instance for
+ *                      it [from device enumeration].
+ *
+ *   hwahc_disconnect()        Remove device instance [from device
+ *                      enumeration].
+ *
+ *   [__]hwahc_op_*()   Host-Wire-Adaptor specific functions for
+ *                      starting/stopping/etc (some might be made also
+ *                      DWA).
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/wait.h>
+#include <linux/completion.h>
+#include "../wa-hc.h"
+#include "../wusbhc.h"
+
+struct hwahc {
+       struct wusbhc wusbhc;   /* has to be 1st */
+       struct wahc wa;
+};
+
+/*
+ * FIXME should be wusbhc
+ *
+ * NOTE: we need to cache the Cluster ID because later...there is no
+ *       way to get it :)
+ */
+static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id)
+{
+       int result;
+       struct wusbhc *wusbhc = &hwahc->wusbhc;
+       struct wahc *wa = &hwahc->wa;
+       struct device *dev = &wa->usb_iface->dev;
+
+       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       WUSB_REQ_SET_CLUSTER_ID,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       cluster_id,
+                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+                       NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (result < 0)
+               dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n",
+                       cluster_id, result);
+       else
+               wusbhc->cluster_id = cluster_id;
+       dev_info(dev, "Wireless USB Cluster ID set to 0x%02x\n", cluster_id);
+       return result;
+}
+
+static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
+{
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct wahc *wa = &hwahc->wa;
+
+       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       WUSB_REQ_SET_NUM_DNTS,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       interval << 8 | slots,
+                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+                       NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * Reset a WUSB host controller and wait for it to complete doing it.
+ *
+ * @usb_hcd:   Pointer to WUSB Host Controller instance.
+ *
+ */
+static int hwahc_op_reset(struct usb_hcd *usb_hcd)
+{
+       int result;
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct device *dev = &hwahc->wa.usb_iface->dev;
+
+       mutex_lock(&wusbhc->mutex);
+       wa_nep_disarm(&hwahc->wa);
+       result = __wa_set_feature(&hwahc->wa, WA_RESET);
+       if (result < 0) {
+               dev_err(dev, "error commanding HC to reset: %d\n", result);
+               goto error_unlock;
+       }
+       result = __wa_wait_status(&hwahc->wa, WA_STATUS_RESETTING, 0);
+       if (result < 0) {
+               dev_err(dev, "error waiting for HC to reset: %d\n", result);
+               goto error_unlock;
+       }
+error_unlock:
+       mutex_unlock(&wusbhc->mutex);
+       return result;
+}
+
+/*
+ * FIXME: break this function up
+ */
+static int hwahc_op_start(struct usb_hcd *usb_hcd)
+{
+       u8 addr;
+       int result;
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+       result = -ENOSPC;
+       mutex_lock(&wusbhc->mutex);
+       addr = wusb_cluster_id_get();
+       if (addr == 0)
+               goto error_cluster_id_get;
+       result = __hwahc_set_cluster_id(hwahc, addr);
+       if (result < 0)
+               goto error_set_cluster_id;
+
+       usb_hcd->uses_new_polling = 1;
+       set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
+       usb_hcd->state = HC_STATE_RUNNING;
+
+       /*
+        * prevent USB core from suspending the root hub since
+        * bus_suspend and bus_resume are not yet supported.
+        */
+       pm_runtime_get_noresume(&usb_hcd->self.root_hub->dev);
+
+       result = 0;
+out:
+       mutex_unlock(&wusbhc->mutex);
+       return result;
+
+error_set_cluster_id:
+       wusb_cluster_id_put(addr);
+error_cluster_id_get:
+       goto out;
+
+}
+
+/*
+ * No need to abort pipes, as when this is called, all the children
+ * has been disconnected and that has done it [through
+ * usb_disable_interface() -> usb_disable_endpoint() ->
+ * hwahc_op_ep_disable() - >rpipe_ep_disable()].
+ */
+static void hwahc_op_stop(struct usb_hcd *usb_hcd)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+
+       mutex_lock(&wusbhc->mutex);
+       wusb_cluster_id_put(wusbhc->cluster_id);
+       mutex_unlock(&wusbhc->mutex);
+}
+
+static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct wahc *wa = &hwahc->wa;
+
+       /*
+        * We cannot query the HWA for the WUSB time since that requires sending
+        * a synchronous URB and this function can be called in_interrupt.
+        * Instead, query the USB frame number for our parent and use that.
+        */
+       return usb_get_current_frame_number(wa->usb_dev);
+}
+
+static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
+                               gfp_t gfp)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+       return wa_urb_enqueue(&hwahc->wa, urb->ep, urb, gfp);
+}
+
+static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb,
+                               int status)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+       return wa_urb_dequeue(&hwahc->wa, urb, status);
+}
+
+/*
+ * Release resources allocated for an endpoint
+ *
+ * If there is an associated rpipe to this endpoint, go ahead and put it.
+ */
+static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd,
+                                     struct usb_host_endpoint *ep)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+       rpipe_ep_disable(&hwahc->wa, ep);
+}
+
+static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
+{
+       int result;
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct device *dev = &hwahc->wa.usb_iface->dev;
+
+       result = __wa_set_feature(&hwahc->wa, WA_ENABLE);
+       if (result < 0) {
+               dev_err(dev, "error commanding HC to start: %d\n", result);
+               goto error_stop;
+       }
+       result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE);
+       if (result < 0) {
+               dev_err(dev, "error waiting for HC to start: %d\n", result);
+               goto error_stop;
+       }
+       result = wa_nep_arm(&hwahc->wa, GFP_KERNEL);
+       if (result < 0) {
+               dev_err(dev, "cannot listen to notifications: %d\n", result);
+               goto error_stop;
+       }
+       /*
+        * If WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS is set,
+        *  disable transfer notifications.
+        */
+       if (hwahc->wa.quirks &
+               WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS) {
+               struct usb_host_interface *cur_altsetting =
+                       hwahc->wa.usb_iface->cur_altsetting;
+
+               result = usb_control_msg(hwahc->wa.usb_dev,
+                               usb_sndctrlpipe(hwahc->wa.usb_dev, 0),
+                               WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS,
+                               USB_DIR_OUT | USB_TYPE_VENDOR |
+                                       USB_RECIP_INTERFACE,
+                               WA_REQ_ALEREON_FEATURE_SET,
+                               cur_altsetting->desc.bInterfaceNumber,
+                               NULL, 0,
+                               USB_CTRL_SET_TIMEOUT);
+               /*
+                * If we successfully sent the control message, start DTI here
+                * because no transfer notifications will be received which is
+                * where DTI is normally started.
+                */
+               if (result == 0)
+                       result = wa_dti_start(&hwahc->wa);
+               else
+                       result = 0;     /* OK.  Continue normally. */
+
+               if (result < 0) {
+                       dev_err(dev, "cannot start DTI: %d\n", result);
+                       goto error_dti_start;
+               }
+       }
+
+       return result;
+
+error_dti_start:
+       wa_nep_disarm(&hwahc->wa);
+error_stop:
+       __wa_clear_feature(&hwahc->wa, WA_ENABLE);
+       return result;
+}
+
+static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay)
+{
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct wahc *wa = &hwahc->wa;
+       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+       int ret;
+
+       ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                             WUSB_REQ_CHAN_STOP,
+                             USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                             delay * 1000,
+                             iface_no,
+                             NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (ret == 0)
+               msleep(delay);
+
+       wa_nep_disarm(&hwahc->wa);
+       __wa_stop(&hwahc->wa);
+}
+
+/*
+ * Set the UWB MAS allocation for the WUSB cluster
+ *
+ * @stream_index: stream to use (-1 for cancelling the allocation)
+ * @mas: mas bitmap to use
+ */
+static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index,
+                             const struct uwb_mas_bm *mas)
+{
+       int result;
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct wahc *wa = &hwahc->wa;
+       struct device *dev = &wa->usb_iface->dev;
+       u8 mas_le[UWB_NUM_MAS/8];
+
+       /* Set the stream index */
+       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       WUSB_REQ_SET_STREAM_IDX,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       stream_index,
+                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+                       NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (result < 0) {
+               dev_err(dev, "Cannot set WUSB stream index: %d\n", result);
+               goto out;
+       }
+       uwb_mas_bm_copy_le(mas_le, mas);
+       /* Set the MAS allocation */
+       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       WUSB_REQ_SET_WUSB_MAS,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+                       mas_le, 32, USB_CTRL_SET_TIMEOUT);
+       if (result < 0)
+               dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result);
+out:
+       return result;
+}
+
+/*
+ * Add an IE to the host's MMC
+ *
+ * @interval:    See WUSB1.0[8.5.3.1]
+ * @repeat_cnt:  See WUSB1.0[8.5.3.1]
+ * @handle:      See WUSB1.0[8.5.3.1]
+ * @wuie:        Pointer to the header of the WUSB IE data to add.
+ *               MUST BE allocated in a kmalloc buffer (no stack or
+ *               vmalloc).
+ *
+ * NOTE: the format of the WUSB IEs for MMCs are different to the
+ *       normal MBOA MAC IEs (IE Id + Length in MBOA MAC vs. Length +
+ *       Id in WUSB IEs). Standards...you gotta love'em.
+ */
+static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval,
+                               u8 repeat_cnt, u8 handle,
+                               struct wuie_hdr *wuie)
+{
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct wahc *wa = &hwahc->wa;
+       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+
+       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       WUSB_REQ_ADD_MMC_IE,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       interval << 8 | repeat_cnt,
+                       handle << 8 | iface_no,
+                       wuie, wuie->bLength, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * Remove an IE to the host's MMC
+ *
+ * @handle:      See WUSB1.0[8.5.3.1]
+ */
+static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
+{
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct wahc *wa = &hwahc->wa;
+       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       WUSB_REQ_REMOVE_MMC_IE,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       0, handle << 8 | iface_no,
+                       NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+/*
+ * Update device information for a given fake port
+ *
+ * @port_idx: Fake port to which device is connected (wusbhc index, not
+ *            USB port number).
+ */
+static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc,
+                                  struct wusb_dev *wusb_dev)
+{
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct wahc *wa = &hwahc->wa;
+       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+       struct hwa_dev_info *dev_info;
+       int ret;
+
+       /* fill out the Device Info buffer and send it */
+       dev_info = kzalloc(sizeof(struct hwa_dev_info), GFP_KERNEL);
+       if (!dev_info)
+               return -ENOMEM;
+       uwb_mas_bm_copy_le(dev_info->bmDeviceAvailability,
+                          &wusb_dev->availability);
+       dev_info->bDeviceAddress = wusb_dev->addr;
+
+       /*
+        * If the descriptors haven't been read yet, use a default PHY
+        * rate of 53.3 Mbit/s only.  The correct value will be used
+        * when this will be called again as part of the
+        * authentication process (which occurs after the descriptors
+        * have been read).
+        */
+       if (wusb_dev->wusb_cap_descr)
+               dev_info->wPHYRates = wusb_dev->wusb_cap_descr->wPHYRates;
+       else
+               dev_info->wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53);
+
+       ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       WUSB_REQ_SET_DEV_INFO,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       0, wusb_dev->port_idx << 8 | iface_no,
+                       dev_info, sizeof(struct hwa_dev_info),
+                       USB_CTRL_SET_TIMEOUT);
+       kfree(dev_info);
+       return ret;
+}
+
+/*
+ * Set host's idea of which encryption (and key) method to use when
+ * talking to ad evice on a given port.
+ *
+ * If key is NULL, it means disable encryption for that "virtual port"
+ * (used when we disconnect).
+ */
+static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+                              const void *key, size_t key_size,
+                              u8 key_idx)
+{
+       int result = -ENOMEM;
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct wahc *wa = &hwahc->wa;
+       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+       struct usb_key_descriptor *keyd;
+       size_t keyd_len;
+
+       keyd_len = sizeof(*keyd) + key_size;
+       keyd = kzalloc(keyd_len, GFP_KERNEL);
+       if (keyd == NULL)
+               return -ENOMEM;
+
+       keyd->bLength = keyd_len;
+       keyd->bDescriptorType = USB_DT_KEY;
+       keyd->tTKID[0] = (tkid >>  0) & 0xff;
+       keyd->tTKID[1] = (tkid >>  8) & 0xff;
+       keyd->tTKID[2] = (tkid >> 16) & 0xff;
+       memcpy(keyd->bKeyData, key, key_size);
+
+       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       USB_REQ_SET_DESCRIPTOR,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       USB_DT_KEY << 8 | key_idx,
+                       port_idx << 8 | iface_no,
+                       keyd, keyd_len, USB_CTRL_SET_TIMEOUT);
+
+       kzfree(keyd); /* clear keys etc. */
+       return result;
+}
+
+/*
+ * Set host's idea of which encryption (and key) method to use when
+ * talking to ad evice on a given port.
+ *
+ * If key is NULL, it means disable encryption for that "virtual port"
+ * (used when we disconnect).
+ */
+static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+                             const void *key, size_t key_size)
+{
+       int result = -ENOMEM;
+       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       struct wahc *wa = &hwahc->wa;
+       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
+       u8 encryption_value;
+
+       /* Tell the host which key to use to talk to the device */
+       if (key) {
+               u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_PTK,
+                                           WUSB_KEY_INDEX_ORIGINATOR_HOST);
+
+               result = __hwahc_dev_set_key(wusbhc, port_idx, tkid,
+                                            key, key_size, key_idx);
+               if (result < 0)
+                       goto error_set_key;
+               encryption_value = wusbhc->ccm1_etd->bEncryptionValue;
+       } else {
+               /* FIXME: this should come from wusbhc->etd[UNSECURE].value */
+               encryption_value = 0;
+       }
+
+       /* Set the encryption type for communicating with the device */
+       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       USB_REQ_SET_ENCRYPTION,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       encryption_value, port_idx << 8 | iface_no,
+                       NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (result < 0)
+               dev_err(wusbhc->dev, "Can't set host's WUSB encryption for "
+                       "port index %u to %s (value %d): %d\n", port_idx,
+                       wusb_et_name(wusbhc->ccm1_etd->bEncryptionType),
+                       wusbhc->ccm1_etd->bEncryptionValue, result);
+error_set_key:
+       return result;
+}
+
+/*
+ * Set host's GTK key
+ */
+static int __hwahc_op_set_gtk(struct wusbhc *wusbhc, u32 tkid,
+                             const void *key, size_t key_size)
+{
+       u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK,
+                                   WUSB_KEY_INDEX_ORIGINATOR_HOST);
+
+       return __hwahc_dev_set_key(wusbhc, 0, tkid, key, key_size, key_idx);
+}
+
+/*
+ * Get the Wire Adapter class-specific descriptor
+ *
+ * NOTE: this descriptor comes with the big bundled configuration
+ *       descriptor that includes the interfaces' and endpoints', so
+ *       we just look for it in the cached copy kept by the USB stack.
+ *
+ * NOTE2: We convert LE fields to CPU order.
+ */
+static int wa_fill_descr(struct wahc *wa)
+{
+       int result;
+       struct device *dev = &wa->usb_iface->dev;
+       char *itr;
+       struct usb_device *usb_dev = wa->usb_dev;
+       struct usb_descriptor_header *hdr;
+       struct usb_wa_descriptor *wa_descr;
+       size_t itr_size, actconfig_idx;
+
+       actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
+                       sizeof(usb_dev->config[0]);
+       itr = usb_dev->rawdescriptors[actconfig_idx];
+       itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
+       while (itr_size >= sizeof(*hdr)) {
+               hdr = (struct usb_descriptor_header *) itr;
+               dev_dbg(dev, "Extra device descriptor: "
+                       "type %02x/%u bytes @ %zu (%zu left)\n",
+                       hdr->bDescriptorType, hdr->bLength,
+                       (itr - usb_dev->rawdescriptors[actconfig_idx]),
+                       itr_size);
+               if (hdr->bDescriptorType == USB_DT_WIRE_ADAPTER)
+                       goto found;
+               itr += hdr->bLength;
+               itr_size -= hdr->bLength;
+       }
+       dev_err(dev, "cannot find Wire Adapter Class descriptor\n");
+       return -ENODEV;
+
+found:
+       result = -EINVAL;
+       if (hdr->bLength > itr_size) {  /* is it available? */
+               dev_err(dev, "incomplete Wire Adapter Class descriptor "
+                       "(%zu bytes left, %u needed)\n",
+                       itr_size, hdr->bLength);
+               goto error;
+       }
+       if (hdr->bLength < sizeof(*wa->wa_descr)) {
+               dev_err(dev, "short Wire Adapter Class descriptor\n");
+               goto error;
+       }
+       wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr;
+       if (le16_to_cpu(wa_descr->bcdWAVersion) > 0x0100)
+               dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n",
+                        (le16_to_cpu(wa_descr->bcdWAVersion) & 0xff00) >> 8,
+                        le16_to_cpu(wa_descr->bcdWAVersion) & 0x00ff);
+       result = 0;
+error:
+       return result;
+}
+
+static const struct hc_driver hwahc_hc_driver = {
+       .description = "hwa-hcd",
+       .product_desc = "Wireless USB HWA host controller",
+       .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd),
+       .irq = NULL,                    /* FIXME */
+       .flags = HCD_USB25,
+       .reset = hwahc_op_reset,
+       .start = hwahc_op_start,
+       .stop = hwahc_op_stop,
+       .get_frame_number = hwahc_op_get_frame_number,
+       .urb_enqueue = hwahc_op_urb_enqueue,
+       .urb_dequeue = hwahc_op_urb_dequeue,
+       .endpoint_disable = hwahc_op_endpoint_disable,
+
+       .hub_status_data = wusbhc_rh_status_data,
+       .hub_control = wusbhc_rh_control,
+       .start_port_reset = wusbhc_rh_start_port_reset,
+};
+
+static int hwahc_security_create(struct hwahc *hwahc)
+{
+       int result;
+       struct wusbhc *wusbhc = &hwahc->wusbhc;
+       struct usb_device *usb_dev = hwahc->wa.usb_dev;
+       struct device *dev = &usb_dev->dev;
+       struct usb_security_descriptor *secd;
+       struct usb_encryption_descriptor *etd;
+       void *itr, *top;
+       size_t itr_size, needed, bytes;
+       u8 index;
+       char buf[64];
+
+       /* Find the host's security descriptors in the config descr bundle */
+       index = (usb_dev->actconfig - usb_dev->config) /
+               sizeof(usb_dev->config[0]);
+       itr = usb_dev->rawdescriptors[index];
+       itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
+       top = itr + itr_size;
+       result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
+                       le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
+                       USB_DT_SECURITY, (void **) &secd, sizeof(*secd));
+       if (result == -1) {
+               dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
+               return 0;
+       }
+       needed = sizeof(*secd);
+       if (top - (void *)secd < needed) {
+               dev_err(dev, "BUG? Not enough data to process security "
+                       "descriptor header (%zu bytes left vs %zu needed)\n",
+                       top - (void *) secd, needed);
+               return 0;
+       }
+       needed = le16_to_cpu(secd->wTotalLength);
+       if (top - (void *)secd < needed) {
+               dev_err(dev, "BUG? Not enough data to process security "
+                       "descriptors (%zu bytes left vs %zu needed)\n",
+                       top - (void *) secd, needed);
+               return 0;
+       }
+       /* Walk over the sec descriptors and store CCM1's on wusbhc */
+       itr = (void *) secd + sizeof(*secd);
+       top = (void *) secd + le16_to_cpu(secd->wTotalLength);
+       index = 0;
+       bytes = 0;
+       while (itr < top) {
+               etd = itr;
+               if (top - itr < sizeof(*etd)) {
+                       dev_err(dev, "BUG: bad host security descriptor; "
+                               "not enough data (%zu vs %zu left)\n",
+                               top - itr, sizeof(*etd));
+                       break;
+               }
+               if (etd->bLength < sizeof(*etd)) {
+                       dev_err(dev, "BUG: bad host encryption descriptor; "
+                               "descriptor is too short "
+                               "(%zu vs %zu needed)\n",
+                               (size_t)etd->bLength, sizeof(*etd));
+                       break;
+               }
+               itr += etd->bLength;
+               bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
+                                 "%s (0x%02x) ",
+                                 wusb_et_name(etd->bEncryptionType),
+                                 etd->bEncryptionValue);
+               wusbhc->ccm1_etd = etd;
+       }
+       dev_info(dev, "supported encryption types: %s\n", buf);
+       if (wusbhc->ccm1_etd == NULL) {
+               dev_err(dev, "E: host doesn't support CCM-1 crypto\n");
+               return 0;
+       }
+       /* Pretty print what we support */
+       return 0;
+}
+
+static void hwahc_security_release(struct hwahc *hwahc)
+{
+       /* nothing to do here so far... */
+}
+
+static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface,
+       kernel_ulong_t quirks)
+{
+       int result;
+       struct device *dev = &iface->dev;
+       struct wusbhc *wusbhc = &hwahc->wusbhc;
+       struct wahc *wa = &hwahc->wa;
+       struct usb_device *usb_dev = interface_to_usbdev(iface);
+
+       wa->usb_dev = usb_get_dev(usb_dev);     /* bind the USB device */
+       wa->usb_iface = usb_get_intf(iface);
+       wusbhc->dev = dev;
+       /* defer getting the uwb_rc handle until it is needed since it
+        * may not have been registered by the hwa_rc driver yet. */
+       wusbhc->uwb_rc = NULL;
+       result = wa_fill_descr(wa);     /* Get the device descriptor */
+       if (result < 0)
+               goto error_fill_descriptor;
+       if (wa->wa_descr->bNumPorts > USB_MAXCHILDREN) {
+               dev_err(dev, "FIXME: USB_MAXCHILDREN too low for WUSB "
+                       "adapter (%u ports)\n", wa->wa_descr->bNumPorts);
+               wusbhc->ports_max = USB_MAXCHILDREN;
+       } else {
+               wusbhc->ports_max = wa->wa_descr->bNumPorts;
+       }
+       wusbhc->mmcies_max = wa->wa_descr->bNumMMCIEs;
+       wusbhc->start = __hwahc_op_wusbhc_start;
+       wusbhc->stop = __hwahc_op_wusbhc_stop;
+       wusbhc->mmcie_add = __hwahc_op_mmcie_add;
+       wusbhc->mmcie_rm = __hwahc_op_mmcie_rm;
+       wusbhc->dev_info_set = __hwahc_op_dev_info_set;
+       wusbhc->bwa_set = __hwahc_op_bwa_set;
+       wusbhc->set_num_dnts = __hwahc_op_set_num_dnts;
+       wusbhc->set_ptk = __hwahc_op_set_ptk;
+       wusbhc->set_gtk = __hwahc_op_set_gtk;
+       result = hwahc_security_create(hwahc);
+       if (result < 0) {
+               dev_err(dev, "Can't initialize security: %d\n", result);
+               goto error_security_create;
+       }
+       wa->wusb = wusbhc;      /* FIXME: ugly, need to fix */
+       result = wusbhc_create(&hwahc->wusbhc);
+       if (result < 0) {
+               dev_err(dev, "Can't create WUSB HC structures: %d\n", result);
+               goto error_wusbhc_create;
+       }
+       result = wa_create(&hwahc->wa, iface, quirks);
+       if (result < 0)
+               goto error_wa_create;
+       return 0;
+
+error_wa_create:
+       wusbhc_destroy(&hwahc->wusbhc);
+error_wusbhc_create:
+       /* WA Descr fill allocs no resources */
+error_security_create:
+error_fill_descriptor:
+       usb_put_intf(iface);
+       usb_put_dev(usb_dev);
+       return result;
+}
+
+static void hwahc_destroy(struct hwahc *hwahc)
+{
+       struct wusbhc *wusbhc = &hwahc->wusbhc;
+
+       mutex_lock(&wusbhc->mutex);
+       __wa_destroy(&hwahc->wa);
+       wusbhc_destroy(&hwahc->wusbhc);
+       hwahc_security_release(hwahc);
+       hwahc->wusbhc.dev = NULL;
+       uwb_rc_put(wusbhc->uwb_rc);
+       usb_put_intf(hwahc->wa.usb_iface);
+       usb_put_dev(hwahc->wa.usb_dev);
+       mutex_unlock(&wusbhc->mutex);
+}
+
+static void hwahc_init(struct hwahc *hwahc)
+{
+       wa_init(&hwahc->wa);
+}
+
+static int hwahc_probe(struct usb_interface *usb_iface,
+                      const struct usb_device_id *id)
+{
+       int result;
+       struct usb_hcd *usb_hcd;
+       struct wusbhc *wusbhc;
+       struct hwahc *hwahc;
+       struct device *dev = &usb_iface->dev;
+
+       result = -ENOMEM;
+       usb_hcd = usb_create_hcd(&hwahc_hc_driver, &usb_iface->dev, "wusb-hwa");
+       if (usb_hcd == NULL) {
+               dev_err(dev, "unable to allocate instance\n");
+               goto error_alloc;
+       }
+       usb_hcd->wireless = 1;
+       usb_hcd->self.sg_tablesize = ~0;
+       wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+       hwahc_init(hwahc);
+       result = hwahc_create(hwahc, usb_iface, id->driver_info);
+       if (result < 0) {
+               dev_err(dev, "Cannot initialize internals: %d\n", result);
+               goto error_hwahc_create;
+       }
+       result = usb_add_hcd(usb_hcd, 0, 0);
+       if (result < 0) {
+               dev_err(dev, "Cannot add HCD: %d\n", result);
+               goto error_add_hcd;
+       }
+       device_wakeup_enable(usb_hcd->self.controller);
+       result = wusbhc_b_create(&hwahc->wusbhc);
+       if (result < 0) {
+               dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result);
+               goto error_wusbhc_b_create;
+       }
+       return 0;
+
+error_wusbhc_b_create:
+       usb_remove_hcd(usb_hcd);
+error_add_hcd:
+       hwahc_destroy(hwahc);
+error_hwahc_create:
+       usb_put_hcd(usb_hcd);
+error_alloc:
+       return result;
+}
+
+static void hwahc_disconnect(struct usb_interface *usb_iface)
+{
+       struct usb_hcd *usb_hcd;
+       struct wusbhc *wusbhc;
+       struct hwahc *hwahc;
+
+       usb_hcd = usb_get_intfdata(usb_iface);
+       wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       hwahc = container_of(wusbhc, struct hwahc, wusbhc);
+
+       wusbhc_b_destroy(&hwahc->wusbhc);
+       usb_remove_hcd(usb_hcd);
+       hwahc_destroy(hwahc);
+       usb_put_hcd(usb_hcd);
+}
+
+static const struct usb_device_id hwahc_id_table[] = {
+       /* Alereon 5310 */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01),
+         .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
+               WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
+       /* Alereon 5611 */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x02, 0x01),
+         .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
+               WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
+       /* FIXME: use class labels for this */
+       { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), },
+       {},
+};
+MODULE_DEVICE_TABLE(usb, hwahc_id_table);
+
+static struct usb_driver hwahc_driver = {
+       .name =         "hwa-hc",
+       .probe =        hwahc_probe,
+       .disconnect =   hwahc_disconnect,
+       .id_table =     hwahc_id_table,
+};
+
+module_usb_driver(hwahc_driver);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Host Wired Adapter USB Host Control Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/host/whci/Makefile b/drivers/staging/wusbcore/host/whci/Makefile
new file mode 100644 (file)
index 0000000..859d200
--- /dev/null
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o
+
+whci-hcd-y := \
+       asl.o   \
+       debug.o \
+       hcd.o   \
+       hw.o    \
+       init.o  \
+       int.o   \
+       pzl.o   \
+       qset.o  \
+       wusb.o
diff --git a/drivers/staging/wusbcore/host/whci/asl.c b/drivers/staging/wusbcore/host/whci/asl.c
new file mode 100644 (file)
index 0000000..a2b9a50
--- /dev/null
@@ -0,0 +1,376 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) asynchronous schedule management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset,
+                              struct whc_qset **next, struct whc_qset **prev)
+{
+       struct list_head *n, *p;
+
+       BUG_ON(list_empty(&whc->async_list));
+
+       n = qset->list_node.next;
+       if (n == &whc->async_list)
+               n = n->next;
+       p = qset->list_node.prev;
+       if (p == &whc->async_list)
+               p = p->prev;
+
+       *next = container_of(n, struct whc_qset, list_node);
+       *prev = container_of(p, struct whc_qset, list_node);
+
+}
+
+static void asl_qset_insert_begin(struct whc *whc, struct whc_qset *qset)
+{
+       list_move(&qset->list_node, &whc->async_list);
+       qset->in_sw_list = true;
+}
+
+static void asl_qset_insert(struct whc *whc, struct whc_qset *qset)
+{
+       struct whc_qset *next, *prev;
+
+       qset_clear(whc, qset);
+
+       /* Link into ASL. */
+       qset_get_next_prev(whc, qset, &next, &prev);
+       whc_qset_set_link_ptr(&qset->qh.link, next->qset_dma);
+       whc_qset_set_link_ptr(&prev->qh.link, qset->qset_dma);
+       qset->in_hw_list = true;
+}
+
+static void asl_qset_remove(struct whc *whc, struct whc_qset *qset)
+{
+       struct whc_qset *prev, *next;
+
+       qset_get_next_prev(whc, qset, &next, &prev);
+
+       list_move(&qset->list_node, &whc->async_removed_list);
+       qset->in_sw_list = false;
+
+       /*
+        * No more qsets in the ASL?  The caller must stop the ASL as
+        * it's no longer valid.
+        */
+       if (list_empty(&whc->async_list))
+               return;
+
+       /* Remove from ASL. */
+       whc_qset_set_link_ptr(&prev->qh.link, next->qset_dma);
+       qset->in_hw_list = false;
+}
+
+/**
+ * process_qset - process any recently inactivated or halted qTDs in a
+ * qset.
+ *
+ * After inactive qTDs are removed, new qTDs can be added if the
+ * urb queue still contains URBs.
+ *
+ * Returns any additional WUSBCMD bits for the ASL sync command (i.e.,
+ * WUSBCMD_ASYNC_QSET_RM if a halted qset was removed).
+ */
+static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
+{
+       enum whc_update update = 0;
+       uint32_t status = 0;
+
+       while (qset->ntds) {
+               struct whc_qtd *td;
+
+               td = &qset->qtd[qset->td_start];
+               status = le32_to_cpu(td->status);
+
+               /*
+                * Nothing to do with a still active qTD.
+                */
+               if (status & QTD_STS_ACTIVE)
+                       break;
+
+               if (status & QTD_STS_HALTED) {
+                       /* Ug, an error. */
+                       process_halted_qtd(whc, qset, td);
+                       /* A halted qTD always triggers an update
+                          because the qset was either removed or
+                          reactivated. */
+                       update |= WHC_UPDATE_UPDATED;
+                       goto done;
+               }
+
+               /* Mmm, a completed qTD. */
+               process_inactive_qtd(whc, qset, td);
+       }
+
+       if (!qset->remove)
+               update |= qset_add_qtds(whc, qset);
+
+done:
+       /*
+        * Remove this qset from the ASL if requested, but only if has
+        * no qTDs.
+        */
+       if (qset->remove && qset->ntds == 0) {
+               asl_qset_remove(whc, qset);
+               update |= WHC_UPDATE_REMOVED;
+       }
+       return update;
+}
+
+void asl_start(struct whc *whc)
+{
+       struct whc_qset *qset;
+
+       qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
+
+       le_writeq(qset->qset_dma | QH_LINK_NTDS(8), whc->base + WUSBASYNCLISTADDR);
+
+       whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, WUSBCMD_ASYNC_EN);
+       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+                     WUSBSTS_ASYNC_SCHED, WUSBSTS_ASYNC_SCHED,
+                     1000, "start ASL");
+}
+
+void asl_stop(struct whc *whc)
+{
+       whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, 0);
+       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+                     WUSBSTS_ASYNC_SCHED, 0,
+                     1000, "stop ASL");
+}
+
+/**
+ * asl_update - request an ASL update and wait for the hardware to be synced
+ * @whc: the WHCI HC
+ * @wusbcmd: WUSBCMD value to start the update.
+ *
+ * If the WUSB HC is inactive (i.e., the ASL is stopped) then the
+ * update must be skipped as the hardware may not respond to update
+ * requests.
+ */
+void asl_update(struct whc *whc, uint32_t wusbcmd)
+{
+       struct wusbhc *wusbhc = &whc->wusbhc;
+       long t;
+
+       mutex_lock(&wusbhc->mutex);
+       if (wusbhc->active) {
+               whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
+               t = wait_event_timeout(
+                       whc->async_list_wq,
+                       (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0,
+                       msecs_to_jiffies(1000));
+               if (t == 0)
+                       whc_hw_error(whc, "ASL update timeout");
+       }
+       mutex_unlock(&wusbhc->mutex);
+}
+
+/**
+ * scan_async_work - scan the ASL for qsets to process.
+ *
+ * Process each qset in the ASL in turn and then signal the WHC that
+ * the ASL has been updated.
+ *
+ * Then start, stop or update the asynchronous schedule as required.
+ */
+void scan_async_work(struct work_struct *work)
+{
+       struct whc *whc = container_of(work, struct whc, async_work);
+       struct whc_qset *qset, *t;
+       enum whc_update update = 0;
+
+       spin_lock_irq(&whc->lock);
+
+       /*
+        * Transerve the software list backwards so new qsets can be
+        * safely inserted into the ASL without making it non-circular.
+        */
+       list_for_each_entry_safe_reverse(qset, t, &whc->async_list, list_node) {
+               if (!qset->in_hw_list) {
+                       asl_qset_insert(whc, qset);
+                       update |= WHC_UPDATE_ADDED;
+               }
+
+               update |= process_qset(whc, qset);
+       }
+
+       spin_unlock_irq(&whc->lock);
+
+       if (update) {
+               uint32_t wusbcmd = WUSBCMD_ASYNC_UPDATED | WUSBCMD_ASYNC_SYNCED_DB;
+               if (update & WHC_UPDATE_REMOVED)
+                       wusbcmd |= WUSBCMD_ASYNC_QSET_RM;
+               asl_update(whc, wusbcmd);
+       }
+
+       /*
+        * Now that the ASL is updated, complete the removal of any
+        * removed qsets.
+        *
+        * If the qset was to be reset, do so and reinsert it into the
+        * ASL if it has pending transfers.
+        */
+       spin_lock_irq(&whc->lock);
+
+       list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
+               qset_remove_complete(whc, qset);
+               if (qset->reset) {
+                       qset_reset(whc, qset);
+                       if (!list_empty(&qset->stds)) {
+                               asl_qset_insert_begin(whc, qset);
+                               queue_work(whc->workqueue, &whc->async_work);
+                       }
+               }
+       }
+
+       spin_unlock_irq(&whc->lock);
+}
+
+/**
+ * asl_urb_enqueue - queue an URB onto the asynchronous list (ASL).
+ * @whc: the WHCI host controller
+ * @urb: the URB to enqueue
+ * @mem_flags: flags for any memory allocations
+ *
+ * The qset for the endpoint is obtained and the urb queued on to it.
+ *
+ * Work is scheduled to update the hardware's view of the ASL.
+ */
+int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
+{
+       struct whc_qset *qset;
+       int err;
+       unsigned long flags;
+
+       spin_lock_irqsave(&whc->lock, flags);
+
+       err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
+       if (err < 0) {
+               spin_unlock_irqrestore(&whc->lock, flags);
+               return err;
+       }
+
+       qset = get_qset(whc, urb, GFP_ATOMIC);
+       if (qset == NULL)
+               err = -ENOMEM;
+       else
+               err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
+       if (!err) {
+               if (!qset->in_sw_list && !qset->remove)
+                       asl_qset_insert_begin(whc, qset);
+       } else
+               usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
+
+       spin_unlock_irqrestore(&whc->lock, flags);
+
+       if (!err)
+               queue_work(whc->workqueue, &whc->async_work);
+
+       return err;
+}
+
+/**
+ * asl_urb_dequeue - remove an URB (qset) from the async list.
+ * @whc: the WHCI host controller
+ * @urb: the URB to dequeue
+ * @status: the current status of the URB
+ *
+ * URBs that do yet have qTDs can simply be removed from the software
+ * queue, otherwise the qset must be removed from the ASL so the qTDs
+ * can be removed.
+ */
+int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
+{
+       struct whc_urb *wurb = urb->hcpriv;
+       struct whc_qset *qset = wurb->qset;
+       struct whc_std *std, *t;
+       bool has_qtd = false;
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&whc->lock, flags);
+
+       ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
+       if (ret < 0)
+               goto out;
+
+       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+               if (std->urb == urb) {
+                       if (std->qtd)
+                               has_qtd = true;
+                       qset_free_std(whc, std);
+               } else
+                       std->qtd = NULL; /* so this std is re-added when the qset is */
+       }
+
+       if (has_qtd) {
+               asl_qset_remove(whc, qset);
+               wurb->status = status;
+               wurb->is_async = true;
+               queue_work(whc->workqueue, &wurb->dequeue_work);
+       } else
+               qset_remove_urb(whc, qset, urb, status);
+out:
+       spin_unlock_irqrestore(&whc->lock, flags);
+
+       return ret;
+}
+
+/**
+ * asl_qset_delete - delete a qset from the ASL
+ */
+void asl_qset_delete(struct whc *whc, struct whc_qset *qset)
+{
+       qset->remove = 1;
+       queue_work(whc->workqueue, &whc->async_work);
+       qset_delete(whc, qset);
+}
+
+/**
+ * asl_init - initialize the asynchronous schedule list
+ *
+ * A dummy qset with no qTDs is added to the ASL to simplify removing
+ * qsets (no need to stop the ASL when the last qset is removed).
+ */
+int asl_init(struct whc *whc)
+{
+       struct whc_qset *qset;
+
+       qset = qset_alloc(whc, GFP_KERNEL);
+       if (qset == NULL)
+               return -ENOMEM;
+
+       asl_qset_insert_begin(whc, qset);
+       asl_qset_insert(whc, qset);
+
+       return 0;
+}
+
+/**
+ * asl_clean_up - free ASL resources
+ *
+ * The ASL is stopped and empty except for the dummy qset.
+ */
+void asl_clean_up(struct whc *whc)
+{
+       struct whc_qset *qset;
+
+       if (!list_empty(&whc->async_list)) {
+               qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
+               list_del(&qset->list_node);
+               qset_free(whc, qset);
+       }
+}
diff --git a/drivers/staging/wusbcore/host/whci/debug.c b/drivers/staging/wusbcore/host/whci/debug.c
new file mode 100644 (file)
index 0000000..443da67
--- /dev/null
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) debug.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/export.h>
+
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+struct whc_dbg {
+       struct dentry *di_f;
+       struct dentry *asl_f;
+       struct dentry *pzl_f;
+};
+
+static void qset_print(struct seq_file *s, struct whc_qset *qset)
+{
+       static const char *qh_type[] = {
+               "ctrl", "isoc", "bulk", "intr", "rsvd", "rsvd", "rsvd", "lpintr", };
+       struct whc_std *std;
+       struct urb *urb = NULL;
+       int i;
+
+       seq_printf(s, "qset %08x", (u32)qset->qset_dma);
+       if (&qset->list_node == qset->whc->async_list.prev) {
+               seq_printf(s, " (dummy)\n");
+       } else {
+               seq_printf(s, " ep%d%s-%s maxpkt: %d\n",
+                          qset->qh.info1 & 0x0f,
+                          (qset->qh.info1 >> 4) & 0x1 ? "in" : "out",
+                          qh_type[(qset->qh.info1 >> 5) & 0x7],
+                          (qset->qh.info1 >> 16) & 0xffff);
+       }
+       seq_printf(s, "  -> %08x\n", (u32)qset->qh.link);
+       seq_printf(s, "  info: %08x %08x %08x\n",
+                  qset->qh.info1, qset->qh.info2,  qset->qh.info3);
+       seq_printf(s, "  sts: %04x errs: %d curwin: %08x\n",
+                  qset->qh.status, qset->qh.err_count, qset->qh.cur_window);
+       seq_printf(s, "  TD: sts: %08x opts: %08x\n",
+                  qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options);
+
+       for (i = 0; i < WHCI_QSET_TD_MAX; i++) {
+               seq_printf(s, "  %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n",
+                       i == qset->td_start ? 'S' : ' ',
+                       i == qset->td_end ? 'E' : ' ',
+                       i, qset->qtd[i].status, qset->qtd[i].options,
+                       (u32)qset->qtd[i].page_list_ptr);
+       }
+       seq_printf(s, "  ntds: %d\n", qset->ntds);
+       list_for_each_entry(std, &qset->stds, list_node) {
+               if (urb != std->urb) {
+                       urb = std->urb;
+                       seq_printf(s, "  urb %p transferred: %d bytes\n", urb,
+                               urb->actual_length);
+               }
+               if (std->qtd)
+                       seq_printf(s, "    sTD[%td]: %zu bytes @ %08x\n",
+                               std->qtd - &qset->qtd[0],
+                               std->len, std->num_pointers ?
+                               (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
+               else
+                       seq_printf(s, "    sTD[-]: %zd bytes @ %08x\n",
+                               std->len, std->num_pointers ?
+                               (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
+       }
+}
+
+static int di_show(struct seq_file *s, void *p)
+{
+       struct whc *whc = s->private;
+       int d;
+
+       for (d = 0; d < whc->n_devices; d++) {
+               struct di_buf_entry *di = &whc->di_buf[d];
+
+               seq_printf(s, "DI[%d]\n", d);
+               seq_printf(s, "  availability: %*pb\n",
+                          UWB_NUM_MAS, (unsigned long *)di->availability_info);
+               seq_printf(s, "  %c%c key idx: %d dev addr: %d\n",
+                          (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
+                          (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
+                          (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
+                          (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
+       }
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(di);
+
+static int asl_show(struct seq_file *s, void *p)
+{
+       struct whc *whc = s->private;
+       struct whc_qset *qset;
+
+       list_for_each_entry(qset, &whc->async_list, list_node) {
+               qset_print(s, qset);
+       }
+
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(asl);
+
+static int pzl_show(struct seq_file *s, void *p)
+{
+       struct whc *whc = s->private;
+       struct whc_qset *qset;
+       int period;
+
+       for (period = 0; period < 5; period++) {
+               seq_printf(s, "Period %d\n", period);
+               list_for_each_entry(qset, &whc->periodic_list[period], list_node) {
+                       qset_print(s, qset);
+               }
+       }
+       return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(pzl);
+
+void whc_dbg_init(struct whc *whc)
+{
+       if (whc->wusbhc.pal.debugfs_dir == NULL)
+               return;
+
+       whc->dbg = kzalloc(sizeof(struct whc_dbg), GFP_KERNEL);
+       if (whc->dbg == NULL)
+               return;
+
+       whc->dbg->di_f = debugfs_create_file("di", 0444,
+                                             whc->wusbhc.pal.debugfs_dir, whc,
+                                             &di_fops);
+       whc->dbg->asl_f = debugfs_create_file("asl", 0444,
+                                             whc->wusbhc.pal.debugfs_dir, whc,
+                                             &asl_fops);
+       whc->dbg->pzl_f = debugfs_create_file("pzl", 0444,
+                                             whc->wusbhc.pal.debugfs_dir, whc,
+                                             &pzl_fops);
+}
+
+void whc_dbg_clean_up(struct whc *whc)
+{
+       if (whc->dbg) {
+               debugfs_remove(whc->dbg->pzl_f);
+               debugfs_remove(whc->dbg->asl_f);
+               debugfs_remove(whc->dbg->di_f);
+               kfree(whc->dbg);
+       }
+}
diff --git a/drivers/staging/wusbcore/host/whci/hcd.c b/drivers/staging/wusbcore/host/whci/hcd.c
new file mode 100644 (file)
index 0000000..bee1ff2
--- /dev/null
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) driver.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+/*
+ * One time initialization.
+ *
+ * Nothing to do here.
+ */
+static int whc_reset(struct usb_hcd *usb_hcd)
+{
+       return 0;
+}
+
+/*
+ * Start the wireless host controller.
+ *
+ * Start device notification.
+ *
+ * Put hc into run state, set DNTS parameters.
+ */
+static int whc_start(struct usb_hcd *usb_hcd)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       u8 bcid;
+       int ret;
+
+       mutex_lock(&wusbhc->mutex);
+
+       le_writel(WUSBINTR_GEN_CMD_DONE
+                 | WUSBINTR_HOST_ERR
+                 | WUSBINTR_ASYNC_SCHED_SYNCED
+                 | WUSBINTR_DNTS_INT
+                 | WUSBINTR_ERR_INT
+                 | WUSBINTR_INT,
+                 whc->base + WUSBINTR);
+
+       /* set cluster ID */
+       bcid = wusb_cluster_id_get();
+       ret = whc_set_cluster_id(whc, bcid);
+       if (ret < 0)
+               goto out;
+       wusbhc->cluster_id = bcid;
+
+       /* start HC */
+       whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN);
+
+       usb_hcd->uses_new_polling = 1;
+       set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
+       usb_hcd->state = HC_STATE_RUNNING;
+
+out:
+       mutex_unlock(&wusbhc->mutex);
+       return ret;
+}
+
+
+/*
+ * Stop the wireless host controller.
+ *
+ * Stop device notification.
+ *
+ * Wait for pending transfer to stop? Put hc into stop state?
+ */
+static void whc_stop(struct usb_hcd *usb_hcd)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+
+       mutex_lock(&wusbhc->mutex);
+
+       /* stop HC */
+       le_writel(0, whc->base + WUSBINTR);
+       whc_write_wusbcmd(whc, WUSBCMD_RUN, 0);
+       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+                     WUSBSTS_HCHALTED, WUSBSTS_HCHALTED,
+                     100, "HC to halt");
+
+       wusb_cluster_id_put(wusbhc->cluster_id);
+
+       mutex_unlock(&wusbhc->mutex);
+}
+
+static int whc_get_frame_number(struct usb_hcd *usb_hcd)
+{
+       /* Frame numbers are not applicable to WUSB. */
+       return -ENOSYS;
+}
+
+
+/*
+ * Queue an URB to the ASL or PZL
+ */
+static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
+                          gfp_t mem_flags)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       int ret;
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_INTERRUPT:
+               ret = pzl_urb_enqueue(whc, urb, mem_flags);
+               break;
+       case PIPE_ISOCHRONOUS:
+               dev_err(&whc->umc->dev, "isochronous transfers unsupported\n");
+               ret = -ENOTSUPP;
+               break;
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+       default:
+               ret = asl_urb_enqueue(whc, urb, mem_flags);
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * Remove a queued URB from the ASL or PZL.
+ */
+static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       int ret;
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_INTERRUPT:
+               ret = pzl_urb_dequeue(whc, urb, status);
+               break;
+       case PIPE_ISOCHRONOUS:
+               ret = -ENOTSUPP;
+               break;
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+       default:
+               ret = asl_urb_dequeue(whc, urb, status);
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * Wait for all URBs to the endpoint to be completed, then delete the
+ * qset.
+ */
+static void whc_endpoint_disable(struct usb_hcd *usb_hcd,
+                                struct usb_host_endpoint *ep)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       struct whc_qset *qset;
+
+       qset = ep->hcpriv;
+       if (qset) {
+               ep->hcpriv = NULL;
+               if (usb_endpoint_xfer_bulk(&ep->desc)
+                   || usb_endpoint_xfer_control(&ep->desc))
+                       asl_qset_delete(whc, qset);
+               else
+                       pzl_qset_delete(whc, qset);
+       }
+}
+
+static void whc_endpoint_reset(struct usb_hcd *usb_hcd,
+                              struct usb_host_endpoint *ep)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       struct whc_qset *qset;
+       unsigned long flags;
+
+       spin_lock_irqsave(&whc->lock, flags);
+
+       qset = ep->hcpriv;
+       if (qset) {
+               qset->remove = 1;
+               qset->reset = 1;
+
+               if (usb_endpoint_xfer_bulk(&ep->desc)
+                   || usb_endpoint_xfer_control(&ep->desc))
+                       queue_work(whc->workqueue, &whc->async_work);
+               else
+                       queue_work(whc->workqueue, &whc->periodic_work);
+       }
+
+       spin_unlock_irqrestore(&whc->lock, flags);
+}
+
+
+static const struct hc_driver whc_hc_driver = {
+       .description = "whci-hcd",
+       .product_desc = "Wireless host controller",
+       .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd),
+       .irq = whc_int_handler,
+       .flags = HCD_USB2,
+
+       .reset = whc_reset,
+       .start = whc_start,
+       .stop = whc_stop,
+       .get_frame_number = whc_get_frame_number,
+       .urb_enqueue = whc_urb_enqueue,
+       .urb_dequeue = whc_urb_dequeue,
+       .endpoint_disable = whc_endpoint_disable,
+       .endpoint_reset = whc_endpoint_reset,
+
+       .hub_status_data = wusbhc_rh_status_data,
+       .hub_control = wusbhc_rh_control,
+       .start_port_reset = wusbhc_rh_start_port_reset,
+};
+
+static int whc_probe(struct umc_dev *umc)
+{
+       int ret;
+       struct usb_hcd *usb_hcd;
+       struct wusbhc *wusbhc;
+       struct whc *whc;
+       struct device *dev = &umc->dev;
+
+       usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci");
+       if (usb_hcd == NULL) {
+               dev_err(dev, "unable to create hcd\n");
+               return -ENOMEM;
+       }
+
+       usb_hcd->wireless = 1;
+       usb_hcd->self.sg_tablesize = 2048; /* somewhat arbitrary */
+
+       wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       whc = wusbhc_to_whc(wusbhc);
+       whc->umc = umc;
+
+       ret = whc_init(whc);
+       if (ret)
+               goto error_whc_init;
+
+       wusbhc->dev = dev;
+       wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent);
+       if (!wusbhc->uwb_rc) {
+               ret = -ENODEV;
+               dev_err(dev, "cannot get radio controller\n");
+               goto error_uwb_rc;
+       }
+
+       if (whc->n_devices > USB_MAXCHILDREN) {
+               dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n",
+                        whc->n_devices);
+               wusbhc->ports_max = USB_MAXCHILDREN;
+       } else
+               wusbhc->ports_max = whc->n_devices;
+       wusbhc->mmcies_max      = whc->n_mmc_ies;
+       wusbhc->start           = whc_wusbhc_start;
+       wusbhc->stop            = whc_wusbhc_stop;
+       wusbhc->mmcie_add       = whc_mmcie_add;
+       wusbhc->mmcie_rm        = whc_mmcie_rm;
+       wusbhc->dev_info_set    = whc_dev_info_set;
+       wusbhc->bwa_set         = whc_bwa_set;
+       wusbhc->set_num_dnts    = whc_set_num_dnts;
+       wusbhc->set_ptk         = whc_set_ptk;
+       wusbhc->set_gtk         = whc_set_gtk;
+
+       ret = wusbhc_create(wusbhc);
+       if (ret)
+               goto error_wusbhc_create;
+
+       ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED);
+       if (ret) {
+               dev_err(dev, "cannot add HCD: %d\n", ret);
+               goto error_usb_add_hcd;
+       }
+       device_wakeup_enable(usb_hcd->self.controller);
+
+       ret = wusbhc_b_create(wusbhc);
+       if (ret) {
+               dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret);
+               goto error_wusbhc_b_create;
+       }
+
+       whc_dbg_init(whc);
+
+       return 0;
+
+error_wusbhc_b_create:
+       usb_remove_hcd(usb_hcd);
+error_usb_add_hcd:
+       wusbhc_destroy(wusbhc);
+error_wusbhc_create:
+       uwb_rc_put(wusbhc->uwb_rc);
+error_uwb_rc:
+       whc_clean_up(whc);
+error_whc_init:
+       usb_put_hcd(usb_hcd);
+       return ret;
+}
+
+
+static void whc_remove(struct umc_dev *umc)
+{
+       struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev);
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+
+       if (usb_hcd) {
+               whc_dbg_clean_up(whc);
+               wusbhc_b_destroy(wusbhc);
+               usb_remove_hcd(usb_hcd);
+               wusbhc_destroy(wusbhc);
+               uwb_rc_put(wusbhc->uwb_rc);
+               whc_clean_up(whc);
+               usb_put_hcd(usb_hcd);
+       }
+}
+
+static struct umc_driver whci_hc_driver = {
+       .name =         "whci-hcd",
+       .cap_id =       UMC_CAP_ID_WHCI_WUSB_HC,
+       .probe =        whc_probe,
+       .remove =       whc_remove,
+};
+
+static int __init whci_hc_driver_init(void)
+{
+       return umc_driver_register(&whci_hc_driver);
+}
+module_init(whci_hc_driver_init);
+
+static void __exit whci_hc_driver_exit(void)
+{
+       umc_driver_unregister(&whci_hc_driver);
+}
+module_exit(whci_hc_driver_exit);
+
+/* PCI device ID's that we handle (so it gets loaded) */
+static struct pci_device_id __used whci_hcd_id_table[] = {
+       { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
+       { /* empty last entry */ }
+};
+MODULE_DEVICE_TABLE(pci, whci_hcd_id_table);
+
+MODULE_DESCRIPTION("WHCI Wireless USB host controller driver");
+MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/host/whci/hw.c b/drivers/staging/wusbcore/host/whci/hw.c
new file mode 100644 (file)
index 0000000..e4e8914
--- /dev/null
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) hardware access helpers.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val)
+{
+       unsigned long flags;
+       u32 cmd;
+
+       spin_lock_irqsave(&whc->lock, flags);
+
+       cmd = le_readl(whc->base + WUSBCMD);
+       cmd = (cmd & ~mask) | val;
+       le_writel(cmd, whc->base + WUSBCMD);
+
+       spin_unlock_irqrestore(&whc->lock, flags);
+}
+
+/**
+ * whc_do_gencmd - start a generic command via the WUSBGENCMDSTS register
+ * @whc:    the WHCI HC
+ * @cmd:    command to start.
+ * @params: parameters for the command (the WUSBGENCMDPARAMS register value).
+ * @addr:   pointer to any data for the command (may be NULL).
+ * @len:    length of the data (if any).
+ */
+int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len)
+{
+       unsigned long flags;
+       dma_addr_t dma_addr;
+       int t;
+       int ret = 0;
+
+       mutex_lock(&whc->mutex);
+
+       /* Wait for previous command to complete. */
+       t = wait_event_timeout(whc->cmd_wq,
+                              (le_readl(whc->base + WUSBGENCMDSTS) & WUSBGENCMDSTS_ACTIVE) == 0,
+                              WHC_GENCMD_TIMEOUT_MS);
+       if (t == 0) {
+               dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n",
+                       le_readl(whc->base + WUSBGENCMDSTS),
+                       le_readl(whc->base + WUSBGENCMDPARAMS));
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+
+       if (addr) {
+               memcpy(whc->gen_cmd_buf, addr, len);
+               dma_addr = whc->gen_cmd_buf_dma;
+       } else
+               dma_addr = 0;
+
+       /* Poke registers to start cmd. */
+       spin_lock_irqsave(&whc->lock, flags);
+
+       le_writel(params, whc->base + WUSBGENCMDPARAMS);
+       le_writeq(dma_addr, whc->base + WUSBGENADDR);
+
+       le_writel(WUSBGENCMDSTS_ACTIVE | WUSBGENCMDSTS_IOC | cmd,
+                 whc->base + WUSBGENCMDSTS);
+
+       spin_unlock_irqrestore(&whc->lock, flags);
+out:
+       mutex_unlock(&whc->mutex);
+
+       return ret;
+}
+
+/**
+ * whc_hw_error - recover from a hardware error
+ * @whc:    the WHCI HC that broke.
+ * @reason: a description of the failure.
+ *
+ * Recover from broken hardware with a full reset.
+ */
+void whc_hw_error(struct whc *whc, const char *reason)
+{
+       struct wusbhc *wusbhc = &whc->wusbhc;
+
+       dev_err(&whc->umc->dev, "hardware error: %s\n", reason);
+       wusbhc_reset_all(wusbhc);
+}
diff --git a/drivers/staging/wusbcore/host/whci/init.c b/drivers/staging/wusbcore/host/whci/init.c
new file mode 100644 (file)
index 0000000..55fd458
--- /dev/null
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) initialization.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/dma-mapping.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+/*
+ * Reset the host controller.
+ */
+static void whc_hw_reset(struct whc *whc)
+{
+       le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD);
+       whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0,
+                     100, "reset");
+}
+
+static void whc_hw_init_di_buf(struct whc *whc)
+{
+       int d;
+
+       /* Disable all entries in the Device Information buffer. */
+       for (d = 0; d < whc->n_devices; d++)
+               whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE;
+
+       le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR);
+}
+
+static void whc_hw_init_dn_buf(struct whc *whc)
+{
+       /* Clear the Device Notification buffer to ensure the V (valid)
+        * bits are clear.  */
+       memset(whc->dn_buf, 0, 4096);
+
+       le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR);
+}
+
+int whc_init(struct whc *whc)
+{
+       u32 whcsparams;
+       int ret, i;
+       resource_size_t start, len;
+
+       spin_lock_init(&whc->lock);
+       mutex_init(&whc->mutex);
+       init_waitqueue_head(&whc->cmd_wq);
+       init_waitqueue_head(&whc->async_list_wq);
+       init_waitqueue_head(&whc->periodic_list_wq);
+       whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0);
+       if (whc->workqueue == NULL) {
+               ret = -ENOMEM;
+               goto error;
+       }
+       INIT_WORK(&whc->dn_work, whc_dn_work);
+
+       INIT_WORK(&whc->async_work, scan_async_work);
+       INIT_LIST_HEAD(&whc->async_list);
+       INIT_LIST_HEAD(&whc->async_removed_list);
+
+       INIT_WORK(&whc->periodic_work, scan_periodic_work);
+       for (i = 0; i < 5; i++)
+               INIT_LIST_HEAD(&whc->periodic_list[i]);
+       INIT_LIST_HEAD(&whc->periodic_removed_list);
+
+       /* Map HC registers. */
+       start = whc->umc->resource.start;
+       len   = whc->umc->resource.end - start + 1;
+       if (!request_mem_region(start, len, "whci-hc")) {
+               dev_err(&whc->umc->dev, "can't request HC region\n");
+               ret = -EBUSY;
+               goto error;
+       }
+       whc->base_phys = start;
+       whc->base = ioremap(start, len);
+       if (!whc->base) {
+               dev_err(&whc->umc->dev, "ioremap\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       whc_hw_reset(whc);
+
+       /* Read maximum number of devices, keys and MMC IEs. */
+       whcsparams = le_readl(whc->base + WHCSPARAMS);
+       whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams);
+       whc->n_keys    = WHCSPARAMS_TO_N_KEYS(whcsparams);
+       whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams);
+
+       dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
+               whc->n_devices, whc->n_keys, whc->n_mmc_ies);
+
+       whc->qset_pool = dma_pool_create("qset", &whc->umc->dev,
+                                        sizeof(struct whc_qset), 64, 0);
+       if (whc->qset_pool == NULL) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       ret = asl_init(whc);
+       if (ret < 0)
+               goto error;
+       ret = pzl_init(whc);
+       if (ret < 0)
+               goto error;
+
+       /* Allocate and initialize a buffer for generic commands, the
+          Device Information buffer, and the Device Notification
+          buffer. */
+
+       whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
+                                             &whc->gen_cmd_buf_dma, GFP_KERNEL);
+       if (whc->gen_cmd_buf == NULL) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       whc->dn_buf = dma_alloc_coherent(&whc->umc->dev,
+                                        sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
+                                        &whc->dn_buf_dma, GFP_KERNEL);
+       if (!whc->dn_buf) {
+               ret = -ENOMEM;
+               goto error;
+       }
+       whc_hw_init_dn_buf(whc);
+
+       whc->di_buf = dma_alloc_coherent(&whc->umc->dev,
+                                        sizeof(struct di_buf_entry) * whc->n_devices,
+                                        &whc->di_buf_dma, GFP_KERNEL);
+       if (!whc->di_buf) {
+               ret = -ENOMEM;
+               goto error;
+       }
+       whc_hw_init_di_buf(whc);
+
+       return 0;
+
+error:
+       whc_clean_up(whc);
+       return ret;
+}
+
+void whc_clean_up(struct whc *whc)
+{
+       resource_size_t len;
+
+       if (whc->di_buf)
+               dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices,
+                                 whc->di_buf, whc->di_buf_dma);
+       if (whc->dn_buf)
+               dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
+                                 whc->dn_buf, whc->dn_buf_dma);
+       if (whc->gen_cmd_buf)
+               dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
+                                 whc->gen_cmd_buf, whc->gen_cmd_buf_dma);
+
+       pzl_clean_up(whc);
+       asl_clean_up(whc);
+
+       dma_pool_destroy(whc->qset_pool);
+
+       len   = resource_size(&whc->umc->resource);
+       if (whc->base)
+               iounmap(whc->base);
+       if (whc->base_phys)
+               release_mem_region(whc->base_phys, len);
+
+       if (whc->workqueue)
+               destroy_workqueue(whc->workqueue);
+}
diff --git a/drivers/staging/wusbcore/host/whci/int.c b/drivers/staging/wusbcore/host/whci/int.c
new file mode 100644 (file)
index 0000000..bdbe35e
--- /dev/null
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) interrupt handling.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+static void transfer_done(struct whc *whc)
+{
+       queue_work(whc->workqueue, &whc->async_work);
+       queue_work(whc->workqueue, &whc->periodic_work);
+}
+
+irqreturn_t whc_int_handler(struct usb_hcd *hcd)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd);
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       u32 sts;
+
+       sts = le_readl(whc->base + WUSBSTS);
+       if (!(sts & WUSBSTS_INT_MASK))
+               return IRQ_NONE;
+       le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS);
+
+       if (sts & WUSBSTS_GEN_CMD_DONE)
+               wake_up(&whc->cmd_wq);
+
+       if (sts & WUSBSTS_HOST_ERR)
+               dev_err(&whc->umc->dev, "FIXME: host system error\n");
+
+       if (sts & WUSBSTS_ASYNC_SCHED_SYNCED)
+               wake_up(&whc->async_list_wq);
+
+       if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED)
+               wake_up(&whc->periodic_list_wq);
+
+       if (sts & WUSBSTS_DNTS_INT)
+               queue_work(whc->workqueue, &whc->dn_work);
+
+       /*
+        * A transfer completed (see [WHCI] section 4.7.1.2 for when
+        * this occurs).
+        */
+       if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT))
+               transfer_done(whc);
+
+       return IRQ_HANDLED;
+}
+
+static int process_dn_buf(struct whc *whc)
+{
+       struct wusbhc *wusbhc = &whc->wusbhc;
+       struct dn_buf_entry *dn;
+       int processed = 0;
+
+       for (dn = whc->dn_buf; dn < whc->dn_buf + WHC_N_DN_ENTRIES; dn++) {
+               if (dn->status & WHC_DN_STATUS_VALID) {
+                       wusbhc_handle_dn(wusbhc, dn->src_addr,
+                                        (struct wusb_dn_hdr *)dn->dn_data,
+                                        dn->msg_size);
+                       dn->status &= ~WHC_DN_STATUS_VALID;
+                       processed++;
+               }
+       }
+       return processed;
+}
+
+void whc_dn_work(struct work_struct *work)
+{
+       struct whc *whc = container_of(work, struct whc, dn_work);
+       int processed;
+
+       do {
+               processed = process_dn_buf(whc);
+       } while (processed);
+}
diff --git a/drivers/staging/wusbcore/host/whci/pzl.c b/drivers/staging/wusbcore/host/whci/pzl.c
new file mode 100644 (file)
index 0000000..6dfc075
--- /dev/null
@@ -0,0 +1,404 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) periodic schedule management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/dma-mapping.h>
+#include <linux/usb.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+static void update_pzl_pointers(struct whc *whc, int period, u64 addr)
+{
+       switch (period) {
+       case 0:
+               whc_qset_set_link_ptr(&whc->pz_list[0], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[2], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[4], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[6], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[8], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[10], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[12], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[14], addr);
+               break;
+       case 1:
+               whc_qset_set_link_ptr(&whc->pz_list[1], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[5], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[9], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[13], addr);
+               break;
+       case 2:
+               whc_qset_set_link_ptr(&whc->pz_list[3], addr);
+               whc_qset_set_link_ptr(&whc->pz_list[11], addr);
+               break;
+       case 3:
+               whc_qset_set_link_ptr(&whc->pz_list[7], addr);
+               break;
+       case 4:
+               whc_qset_set_link_ptr(&whc->pz_list[15], addr);
+               break;
+       }
+}
+
+/*
+ * Return the 'period' to use for this qset.  The minimum interval for
+ * the endpoint is used so whatever urbs are submitted the device is
+ * polled often enough.
+ */
+static int qset_get_period(struct whc *whc, struct whc_qset *qset)
+{
+       uint8_t bInterval = qset->ep->desc.bInterval;
+
+       if (bInterval < 6)
+               bInterval = 6;
+       if (bInterval > 10)
+               bInterval = 10;
+       return bInterval - 6;
+}
+
+static void qset_insert_in_sw_list(struct whc *whc, struct whc_qset *qset)
+{
+       int period;
+
+       period = qset_get_period(whc, qset);
+
+       qset_clear(whc, qset);
+       list_move(&qset->list_node, &whc->periodic_list[period]);
+       qset->in_sw_list = true;
+}
+
+static void pzl_qset_remove(struct whc *whc, struct whc_qset *qset)
+{
+       list_move(&qset->list_node, &whc->periodic_removed_list);
+       qset->in_hw_list = false;
+       qset->in_sw_list = false;
+}
+
+/**
+ * pzl_process_qset - process any recently inactivated or halted qTDs
+ * in a qset.
+ *
+ * After inactive qTDs are removed, new qTDs can be added if the
+ * urb queue still contains URBs.
+ *
+ * Returns the schedule updates required.
+ */
+static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
+{
+       enum whc_update update = 0;
+       uint32_t status = 0;
+
+       while (qset->ntds) {
+               struct whc_qtd *td;
+
+               td = &qset->qtd[qset->td_start];
+               status = le32_to_cpu(td->status);
+
+               /*
+                * Nothing to do with a still active qTD.
+                */
+               if (status & QTD_STS_ACTIVE)
+                       break;
+
+               if (status & QTD_STS_HALTED) {
+                       /* Ug, an error. */
+                       process_halted_qtd(whc, qset, td);
+                       /* A halted qTD always triggers an update
+                          because the qset was either removed or
+                          reactivated. */
+                       update |= WHC_UPDATE_UPDATED;
+                       goto done;
+               }
+
+               /* Mmm, a completed qTD. */
+               process_inactive_qtd(whc, qset, td);
+       }
+
+       if (!qset->remove)
+               update |= qset_add_qtds(whc, qset);
+
+done:
+       /*
+        * If there are no qTDs in this qset, remove it from the PZL.
+        */
+       if (qset->remove && qset->ntds == 0) {
+               pzl_qset_remove(whc, qset);
+               update |= WHC_UPDATE_REMOVED;
+       }
+
+       return update;
+}
+
+/**
+ * pzl_start - start the periodic schedule
+ * @whc: the WHCI host controller
+ *
+ * The PZL must be valid (e.g., all entries in the list should have
+ * the T bit set).
+ */
+void pzl_start(struct whc *whc)
+{
+       le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
+
+       whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, WUSBCMD_PERIODIC_EN);
+       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+                     WUSBSTS_PERIODIC_SCHED, WUSBSTS_PERIODIC_SCHED,
+                     1000, "start PZL");
+}
+
+/**
+ * pzl_stop - stop the periodic schedule
+ * @whc: the WHCI host controller
+ */
+void pzl_stop(struct whc *whc)
+{
+       whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, 0);
+       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
+                     WUSBSTS_PERIODIC_SCHED, 0,
+                     1000, "stop PZL");
+}
+
+/**
+ * pzl_update - request a PZL update and wait for the hardware to be synced
+ * @whc: the WHCI HC
+ * @wusbcmd: WUSBCMD value to start the update.
+ *
+ * If the WUSB HC is inactive (i.e., the PZL is stopped) then the
+ * update must be skipped as the hardware may not respond to update
+ * requests.
+ */
+void pzl_update(struct whc *whc, uint32_t wusbcmd)
+{
+       struct wusbhc *wusbhc = &whc->wusbhc;
+       long t;
+
+       mutex_lock(&wusbhc->mutex);
+       if (wusbhc->active) {
+               whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
+               t = wait_event_timeout(
+                       whc->periodic_list_wq,
+                       (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0,
+                       msecs_to_jiffies(1000));
+               if (t == 0)
+                       whc_hw_error(whc, "PZL update timeout");
+       }
+       mutex_unlock(&wusbhc->mutex);
+}
+
+static void update_pzl_hw_view(struct whc *whc)
+{
+       struct whc_qset *qset, *t;
+       int period;
+       u64 tmp_qh = 0;
+
+       for (period = 0; period < 5; period++) {
+               list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
+                       whc_qset_set_link_ptr(&qset->qh.link, tmp_qh);
+                       tmp_qh = qset->qset_dma;
+                       qset->in_hw_list = true;
+               }
+               update_pzl_pointers(whc, period, tmp_qh);
+       }
+}
+
+/**
+ * scan_periodic_work - scan the PZL for qsets to process.
+ *
+ * Process each qset in the PZL in turn and then signal the WHC that
+ * the PZL has been updated.
+ *
+ * Then start, stop or update the periodic schedule as required.
+ */
+void scan_periodic_work(struct work_struct *work)
+{
+       struct whc *whc = container_of(work, struct whc, periodic_work);
+       struct whc_qset *qset, *t;
+       enum whc_update update = 0;
+       int period;
+
+       spin_lock_irq(&whc->lock);
+
+       for (period = 4; period >= 0; period--) {
+               list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
+                       if (!qset->in_hw_list)
+                               update |= WHC_UPDATE_ADDED;
+                       update |= pzl_process_qset(whc, qset);
+               }
+       }
+
+       if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED))
+               update_pzl_hw_view(whc);
+
+       spin_unlock_irq(&whc->lock);
+
+       if (update) {
+               uint32_t wusbcmd = WUSBCMD_PERIODIC_UPDATED | WUSBCMD_PERIODIC_SYNCED_DB;
+               if (update & WHC_UPDATE_REMOVED)
+                       wusbcmd |= WUSBCMD_PERIODIC_QSET_RM;
+               pzl_update(whc, wusbcmd);
+       }
+
+       /*
+        * Now that the PZL is updated, complete the removal of any
+        * removed qsets.
+        *
+        * If the qset was to be reset, do so and reinsert it into the
+        * PZL if it has pending transfers.
+        */
+       spin_lock_irq(&whc->lock);
+
+       list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
+               qset_remove_complete(whc, qset);
+               if (qset->reset) {
+                       qset_reset(whc, qset);
+                       if (!list_empty(&qset->stds)) {
+                               qset_insert_in_sw_list(whc, qset);
+                               queue_work(whc->workqueue, &whc->periodic_work);
+                       }
+               }
+       }
+
+       spin_unlock_irq(&whc->lock);
+}
+
+/**
+ * pzl_urb_enqueue - queue an URB onto the periodic list (PZL)
+ * @whc: the WHCI host controller
+ * @urb: the URB to enqueue
+ * @mem_flags: flags for any memory allocations
+ *
+ * The qset for the endpoint is obtained and the urb queued on to it.
+ *
+ * Work is scheduled to update the hardware's view of the PZL.
+ */
+int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
+{
+       struct whc_qset *qset;
+       int err;
+       unsigned long flags;
+
+       spin_lock_irqsave(&whc->lock, flags);
+
+       err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
+       if (err < 0) {
+               spin_unlock_irqrestore(&whc->lock, flags);
+               return err;
+       }
+
+       qset = get_qset(whc, urb, GFP_ATOMIC);
+       if (qset == NULL)
+               err = -ENOMEM;
+       else
+               err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
+       if (!err) {
+               if (!qset->in_sw_list && !qset->remove)
+                       qset_insert_in_sw_list(whc, qset);
+       } else
+               usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
+
+       spin_unlock_irqrestore(&whc->lock, flags);
+
+       if (!err)
+               queue_work(whc->workqueue, &whc->periodic_work);
+
+       return err;
+}
+
+/**
+ * pzl_urb_dequeue - remove an URB (qset) from the periodic list
+ * @whc: the WHCI host controller
+ * @urb: the URB to dequeue
+ * @status: the current status of the URB
+ *
+ * URBs that do yet have qTDs can simply be removed from the software
+ * queue, otherwise the qset must be removed so the qTDs can be safely
+ * removed.
+ */
+int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
+{
+       struct whc_urb *wurb = urb->hcpriv;
+       struct whc_qset *qset = wurb->qset;
+       struct whc_std *std, *t;
+       bool has_qtd = false;
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&whc->lock, flags);
+
+       ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
+       if (ret < 0)
+               goto out;
+
+       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+               if (std->urb == urb) {
+                       if (std->qtd)
+                               has_qtd = true;
+                       qset_free_std(whc, std);
+               } else
+                       std->qtd = NULL; /* so this std is re-added when the qset is */
+       }
+
+       if (has_qtd) {
+               pzl_qset_remove(whc, qset);
+               update_pzl_hw_view(whc);
+               wurb->status = status;
+               wurb->is_async = false;
+               queue_work(whc->workqueue, &wurb->dequeue_work);
+       } else
+               qset_remove_urb(whc, qset, urb, status);
+out:
+       spin_unlock_irqrestore(&whc->lock, flags);
+
+       return ret;
+}
+
+/**
+ * pzl_qset_delete - delete a qset from the PZL
+ */
+void pzl_qset_delete(struct whc *whc, struct whc_qset *qset)
+{
+       qset->remove = 1;
+       queue_work(whc->workqueue, &whc->periodic_work);
+       qset_delete(whc, qset);
+}
+
+/**
+ * pzl_init - initialize the periodic zone list
+ * @whc: the WHCI host controller
+ */
+int pzl_init(struct whc *whc)
+{
+       int i;
+
+       whc->pz_list = dma_alloc_coherent(&whc->umc->dev, sizeof(u64) * 16,
+                                         &whc->pz_list_dma, GFP_KERNEL);
+       if (whc->pz_list == NULL)
+               return -ENOMEM;
+
+       /* Set T bit on all elements in PZL. */
+       for (i = 0; i < 16; i++)
+               whc->pz_list[i] = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
+
+       le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
+
+       return 0;
+}
+
+/**
+ * pzl_clean_up - free PZL resources
+ * @whc: the WHCI host controller
+ *
+ * The PZL is stopped and empty.
+ */
+void pzl_clean_up(struct whc *whc)
+{
+       if (whc->pz_list)
+               dma_free_coherent(&whc->umc->dev,  sizeof(u64) * 16, whc->pz_list,
+                                 whc->pz_list_dma);
+}
diff --git a/drivers/staging/wusbcore/host/whci/qset.c b/drivers/staging/wusbcore/host/whci/qset.c
new file mode 100644 (file)
index 0000000..66459b7
--- /dev/null
@@ -0,0 +1,831 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) qset management.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags)
+{
+       struct whc_qset *qset;
+       dma_addr_t dma;
+
+       qset = dma_pool_zalloc(whc->qset_pool, mem_flags, &dma);
+       if (qset == NULL)
+               return NULL;
+
+       qset->qset_dma = dma;
+       qset->whc = whc;
+
+       INIT_LIST_HEAD(&qset->list_node);
+       INIT_LIST_HEAD(&qset->stds);
+
+       return qset;
+}
+
+/**
+ * qset_fill_qh - fill the static endpoint state in a qset's QHead
+ * @qset: the qset whose QH needs initializing with static endpoint
+ *        state
+ * @urb:  an urb for a transfer to this endpoint
+ */
+static void qset_fill_qh(struct whc *whc, struct whc_qset *qset, struct urb *urb)
+{
+       struct usb_device *usb_dev = urb->dev;
+       struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
+       struct usb_wireless_ep_comp_descriptor *epcd;
+       bool is_out;
+       uint8_t phy_rate;
+
+       is_out = usb_pipeout(urb->pipe);
+
+       qset->max_packet = le16_to_cpu(urb->ep->desc.wMaxPacketSize);
+
+       epcd = (struct usb_wireless_ep_comp_descriptor *)qset->ep->extra;
+       if (epcd) {
+               qset->max_seq = epcd->bMaxSequence;
+               qset->max_burst = epcd->bMaxBurst;
+       } else {
+               qset->max_seq = 2;
+               qset->max_burst = 1;
+       }
+
+       /*
+        * Initial PHY rate is 53.3 Mbit/s for control endpoints or
+        * the maximum supported by the device for other endpoints
+        * (unless limited by the user).
+        */
+       if (usb_pipecontrol(urb->pipe))
+               phy_rate = UWB_PHY_RATE_53;
+       else {
+               uint16_t phy_rates;
+
+               phy_rates = le16_to_cpu(wusb_dev->wusb_cap_descr->wPHYRates);
+               phy_rate = fls(phy_rates) - 1;
+               if (phy_rate > whc->wusbhc.phy_rate)
+                       phy_rate = whc->wusbhc.phy_rate;
+       }
+
+       qset->qh.info1 = cpu_to_le32(
+               QH_INFO1_EP(usb_pipeendpoint(urb->pipe))
+               | (is_out ? QH_INFO1_DIR_OUT : QH_INFO1_DIR_IN)
+               | usb_pipe_to_qh_type(urb->pipe)
+               | QH_INFO1_DEV_INFO_IDX(wusb_port_no_to_idx(usb_dev->portnum))
+               | QH_INFO1_MAX_PKT_LEN(qset->max_packet)
+               );
+       qset->qh.info2 = cpu_to_le32(
+               QH_INFO2_BURST(qset->max_burst)
+               | QH_INFO2_DBP(0)
+               | QH_INFO2_MAX_COUNT(3)
+               | QH_INFO2_MAX_RETRY(3)
+               | QH_INFO2_MAX_SEQ(qset->max_seq - 1)
+               );
+       /* FIXME: where can we obtain these Tx parameters from?  Why
+        * doesn't the chip know what Tx power to use? It knows the Rx
+        * strength and can presumably guess the Tx power required
+        * from that? */
+       qset->qh.info3 = cpu_to_le32(
+               QH_INFO3_TX_RATE(phy_rate)
+               | QH_INFO3_TX_PWR(0) /* 0 == max power */
+               );
+
+       qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
+}
+
+/**
+ * qset_clear - clear fields in a qset so it may be reinserted into a
+ * schedule.
+ *
+ * The sequence number and current window are not cleared (see
+ * qset_reset()).
+ */
+void qset_clear(struct whc *whc, struct whc_qset *qset)
+{
+       qset->td_start = qset->td_end = qset->ntds = 0;
+
+       qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
+       qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
+       qset->qh.err_count = 0;
+       qset->qh.scratch[0] = 0;
+       qset->qh.scratch[1] = 0;
+       qset->qh.scratch[2] = 0;
+
+       memset(&qset->qh.overlay, 0, sizeof(qset->qh.overlay));
+
+       init_completion(&qset->remove_complete);
+}
+
+/**
+ * qset_reset - reset endpoint state in a qset.
+ *
+ * Clears the sequence number and current window.  This qset must not
+ * be in the ASL or PZL.
+ */
+void qset_reset(struct whc *whc, struct whc_qset *qset)
+{
+       qset->reset = 0;
+
+       qset->qh.status &= ~QH_STATUS_SEQ_MASK;
+       qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
+}
+
+/**
+ * get_qset - get the qset for an async endpoint
+ *
+ * A new qset is created if one does not already exist.
+ */
+struct whc_qset *get_qset(struct whc *whc, struct urb *urb,
+                                gfp_t mem_flags)
+{
+       struct whc_qset *qset;
+
+       qset = urb->ep->hcpriv;
+       if (qset == NULL) {
+               qset = qset_alloc(whc, mem_flags);
+               if (qset == NULL)
+                       return NULL;
+
+               qset->ep = urb->ep;
+               urb->ep->hcpriv = qset;
+               qset_fill_qh(whc, qset, urb);
+       }
+       return qset;
+}
+
+void qset_remove_complete(struct whc *whc, struct whc_qset *qset)
+{
+       qset->remove = 0;
+       list_del_init(&qset->list_node);
+       complete(&qset->remove_complete);
+}
+
+/**
+ * qset_add_qtds - add qTDs for an URB to a qset
+ *
+ * Returns true if the list (ASL/PZL) must be updated because (for a
+ * WHCI 0.95 controller) an activated qTD was pointed to be iCur.
+ */
+enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset)
+{
+       struct whc_std *std;
+       enum whc_update update = 0;
+
+       list_for_each_entry(std, &qset->stds, list_node) {
+               struct whc_qtd *qtd;
+               uint32_t status;
+
+               if (qset->ntds >= WHCI_QSET_TD_MAX
+                   || (qset->pause_after_urb && std->urb != qset->pause_after_urb))
+                       break;
+
+               if (std->qtd)
+                       continue; /* already has a qTD */
+
+               qtd = std->qtd = &qset->qtd[qset->td_end];
+
+               /* Fill in setup bytes for control transfers. */
+               if (usb_pipecontrol(std->urb->pipe))
+                       memcpy(qtd->setup, std->urb->setup_packet, 8);
+
+               status = QTD_STS_ACTIVE | QTD_STS_LEN(std->len);
+
+               if (whc_std_last(std) && usb_pipeout(std->urb->pipe))
+                       status |= QTD_STS_LAST_PKT;
+
+               /*
+                * For an IN transfer the iAlt field should be set so
+                * the h/w will automatically advance to the next
+                * transfer. However, if there are 8 or more TDs
+                * remaining in this transfer then iAlt cannot be set
+                * as it could point to somewhere in this transfer.
+                */
+               if (std->ntds_remaining < WHCI_QSET_TD_MAX) {
+                       int ialt;
+                       ialt = (qset->td_end + std->ntds_remaining) % WHCI_QSET_TD_MAX;
+                       status |= QTD_STS_IALT(ialt);
+               } else if (usb_pipein(std->urb->pipe))
+                       qset->pause_after_urb = std->urb;
+
+               if (std->num_pointers)
+                       qtd->options = cpu_to_le32(QTD_OPT_IOC);
+               else
+                       qtd->options = cpu_to_le32(QTD_OPT_IOC | QTD_OPT_SMALL);
+               qtd->page_list_ptr = cpu_to_le64(std->dma_addr);
+
+               qtd->status = cpu_to_le32(status);
+
+               if (QH_STATUS_TO_ICUR(qset->qh.status) == qset->td_end)
+                       update = WHC_UPDATE_UPDATED;
+
+               if (++qset->td_end >= WHCI_QSET_TD_MAX)
+                       qset->td_end = 0;
+               qset->ntds++;
+       }
+
+       return update;
+}
+
+/**
+ * qset_remove_qtd - remove the first qTD from a qset.
+ *
+ * The qTD might be still active (if it's part of a IN URB that
+ * resulted in a short read) so ensure it's deactivated.
+ */
+static void qset_remove_qtd(struct whc *whc, struct whc_qset *qset)
+{
+       qset->qtd[qset->td_start].status = 0;
+
+       if (++qset->td_start >= WHCI_QSET_TD_MAX)
+               qset->td_start = 0;
+       qset->ntds--;
+}
+
+static void qset_copy_bounce_to_sg(struct whc *whc, struct whc_std *std)
+{
+       struct scatterlist *sg;
+       void *bounce;
+       size_t remaining, offset;
+
+       bounce = std->bounce_buf;
+       remaining = std->len;
+
+       sg = std->bounce_sg;
+       offset = std->bounce_offset;
+
+       while (remaining) {
+               size_t len;
+
+               len = min(sg->length - offset, remaining);
+               memcpy(sg_virt(sg) + offset, bounce, len);
+
+               bounce += len;
+               remaining -= len;
+
+               offset += len;
+               if (offset >= sg->length) {
+                       sg = sg_next(sg);
+                       offset = 0;
+               }
+       }
+
+}
+
+/**
+ * qset_free_std - remove an sTD and free it.
+ * @whc: the WHCI host controller
+ * @std: the sTD to remove and free.
+ */
+void qset_free_std(struct whc *whc, struct whc_std *std)
+{
+       list_del(&std->list_node);
+       if (std->bounce_buf) {
+               bool is_out = usb_pipeout(std->urb->pipe);
+               dma_addr_t dma_addr;
+
+               if (std->num_pointers)
+                       dma_addr = le64_to_cpu(std->pl_virt[0].buf_ptr);
+               else
+                       dma_addr = std->dma_addr;
+
+               dma_unmap_single(whc->wusbhc.dev, dma_addr,
+                                std->len, is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               if (!is_out)
+                       qset_copy_bounce_to_sg(whc, std);
+               kfree(std->bounce_buf);
+       }
+       if (std->pl_virt) {
+               if (!dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
+                       dma_unmap_single(whc->wusbhc.dev, std->dma_addr,
+                                        std->num_pointers * sizeof(struct whc_page_list_entry),
+                                        DMA_TO_DEVICE);
+               kfree(std->pl_virt);
+               std->pl_virt = NULL;
+       }
+       kfree(std);
+}
+
+/**
+ * qset_remove_qtds - remove an URB's qTDs (and sTDs).
+ */
+static void qset_remove_qtds(struct whc *whc, struct whc_qset *qset,
+                            struct urb *urb)
+{
+       struct whc_std *std, *t;
+
+       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+               if (std->urb != urb)
+                       break;
+               if (std->qtd != NULL)
+                       qset_remove_qtd(whc, qset);
+               qset_free_std(whc, std);
+       }
+}
+
+/**
+ * qset_free_stds - free any remaining sTDs for an URB.
+ */
+static void qset_free_stds(struct whc_qset *qset, struct urb *urb)
+{
+       struct whc_std *std, *t;
+
+       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
+               if (std->urb == urb)
+                       qset_free_std(qset->whc, std);
+       }
+}
+
+static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_flags)
+{
+       dma_addr_t dma_addr = std->dma_addr;
+       dma_addr_t sp, ep;
+       size_t pl_len;
+       int p;
+
+       /* Short buffers don't need a page list. */
+       if (std->len <= WHCI_PAGE_SIZE) {
+               std->num_pointers = 0;
+               return 0;
+       }
+
+       sp = dma_addr & ~(WHCI_PAGE_SIZE-1);
+       ep = dma_addr + std->len;
+       std->num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
+
+       pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
+       std->pl_virt = kmalloc(pl_len, mem_flags);
+       if (std->pl_virt == NULL)
+               return -ENOMEM;
+       std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE);
+       if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) {
+               kfree(std->pl_virt);
+               return -EFAULT;
+       }
+
+       for (p = 0; p < std->num_pointers; p++) {
+               std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
+               dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
+       }
+
+       return 0;
+}
+
+/**
+ * urb_dequeue_work - executes asl/pzl update and gives back the urb to the system.
+ */
+static void urb_dequeue_work(struct work_struct *work)
+{
+       struct whc_urb *wurb = container_of(work, struct whc_urb, dequeue_work);
+       struct whc_qset *qset = wurb->qset;
+       struct whc *whc = qset->whc;
+       unsigned long flags;
+
+       if (wurb->is_async)
+               asl_update(whc, WUSBCMD_ASYNC_UPDATED
+                          | WUSBCMD_ASYNC_SYNCED_DB
+                          | WUSBCMD_ASYNC_QSET_RM);
+       else
+               pzl_update(whc, WUSBCMD_PERIODIC_UPDATED
+                          | WUSBCMD_PERIODIC_SYNCED_DB
+                          | WUSBCMD_PERIODIC_QSET_RM);
+
+       spin_lock_irqsave(&whc->lock, flags);
+       qset_remove_urb(whc, qset, wurb->urb, wurb->status);
+       spin_unlock_irqrestore(&whc->lock, flags);
+}
+
+static struct whc_std *qset_new_std(struct whc *whc, struct whc_qset *qset,
+                                   struct urb *urb, gfp_t mem_flags)
+{
+       struct whc_std *std;
+
+       std = kzalloc(sizeof(struct whc_std), mem_flags);
+       if (std == NULL)
+               return NULL;
+
+       std->urb = urb;
+       std->qtd = NULL;
+
+       INIT_LIST_HEAD(&std->list_node);
+       list_add_tail(&std->list_node, &qset->stds);
+
+       return std;
+}
+
+static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *urb,
+                          gfp_t mem_flags)
+{
+       size_t remaining;
+       struct scatterlist *sg;
+       int i;
+       int ntds = 0;
+       struct whc_std *std = NULL;
+       struct whc_page_list_entry *new_pl_virt;
+       dma_addr_t prev_end = 0;
+       size_t pl_len;
+       int p = 0;
+
+       remaining = urb->transfer_buffer_length;
+
+       for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
+               dma_addr_t dma_addr;
+               size_t dma_remaining;
+               dma_addr_t sp, ep;
+               int num_pointers;
+
+               if (remaining == 0) {
+                       break;
+               }
+
+               dma_addr = sg_dma_address(sg);
+               dma_remaining = min_t(size_t, sg_dma_len(sg), remaining);
+
+               while (dma_remaining) {
+                       size_t dma_len;
+
+                       /*
+                        * We can use the previous std (if it exists) provided that:
+                        * - the previous one ended on a page boundary.
+                        * - the current one begins on a page boundary.
+                        * - the previous one isn't full.
+                        *
+                        * If a new std is needed but the previous one
+                        * was not a whole number of packets then this
+                        * sg list cannot be mapped onto multiple
+                        * qTDs.  Return an error and let the caller
+                        * sort it out.
+                        */
+                       if (!std
+                           || (prev_end & (WHCI_PAGE_SIZE-1))
+                           || (dma_addr & (WHCI_PAGE_SIZE-1))
+                           || std->len + WHCI_PAGE_SIZE > QTD_MAX_XFER_SIZE) {
+                               if (std && std->len % qset->max_packet != 0)
+                                       return -EINVAL;
+                               std = qset_new_std(whc, qset, urb, mem_flags);
+                               if (std == NULL) {
+                                       return -ENOMEM;
+                               }
+                               ntds++;
+                               p = 0;
+                       }
+
+                       dma_len = dma_remaining;
+
+                       /*
+                        * If the remainder of this element doesn't
+                        * fit in a single qTD, limit the qTD to a
+                        * whole number of packets.  This allows the
+                        * remainder to go into the next qTD.
+                        */
+                       if (std->len + dma_len > QTD_MAX_XFER_SIZE) {
+                               dma_len = (QTD_MAX_XFER_SIZE / qset->max_packet)
+                                       * qset->max_packet - std->len;
+                       }
+
+                       std->len += dma_len;
+                       std->ntds_remaining = -1; /* filled in later */
+
+                       sp = dma_addr & ~(WHCI_PAGE_SIZE-1);
+                       ep = dma_addr + dma_len;
+                       num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
+                       std->num_pointers += num_pointers;
+
+                       pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
+
+                       new_pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
+                       if (new_pl_virt == NULL) {
+                               kfree(std->pl_virt);
+                               std->pl_virt = NULL;
+                               return -ENOMEM;
+                       }
+                       std->pl_virt = new_pl_virt;
+
+                       for (;p < std->num_pointers; p++) {
+                               std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
+                               dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
+                       }
+
+                       prev_end = dma_addr = ep;
+                       dma_remaining -= dma_len;
+                       remaining -= dma_len;
+               }
+       }
+
+       /* Now the number of stds is know, go back and fill in
+          std->ntds_remaining. */
+       list_for_each_entry(std, &qset->stds, list_node) {
+               if (std->ntds_remaining == -1) {
+                       pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
+                       std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt,
+                                                      pl_len, DMA_TO_DEVICE);
+                       if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
+                               return -EFAULT;
+                       std->ntds_remaining = ntds--;
+               }
+       }
+       return 0;
+}
+
+/**
+ * qset_add_urb_sg_linearize - add an urb with sg list, copying the data
+ *
+ * If the URB contains an sg list whose elements cannot be directly
+ * mapped to qTDs then the data must be transferred via bounce
+ * buffers.
+ */
+static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,
+                                    struct urb *urb, gfp_t mem_flags)
+{
+       bool is_out = usb_pipeout(urb->pipe);
+       size_t max_std_len;
+       size_t remaining;
+       int ntds = 0;
+       struct whc_std *std = NULL;
+       void *bounce = NULL;
+       struct scatterlist *sg;
+       int i;
+
+       /* limit maximum bounce buffer to 16 * 3.5 KiB ~= 28 k */
+       max_std_len = qset->max_burst * qset->max_packet;
+
+       remaining = urb->transfer_buffer_length;
+
+       for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
+               size_t len;
+               size_t sg_remaining;
+               void *orig;
+
+               if (remaining == 0) {
+                       break;
+               }
+
+               sg_remaining = min_t(size_t, remaining, sg->length);
+               orig = sg_virt(sg);
+
+               while (sg_remaining) {
+                       if (!std || std->len == max_std_len) {
+                               std = qset_new_std(whc, qset, urb, mem_flags);
+                               if (std == NULL)
+                                       return -ENOMEM;
+                               std->bounce_buf = kmalloc(max_std_len, mem_flags);
+                               if (std->bounce_buf == NULL)
+                                       return -ENOMEM;
+                               std->bounce_sg = sg;
+                               std->bounce_offset = orig - sg_virt(sg);
+                               bounce = std->bounce_buf;
+                               ntds++;
+                       }
+
+                       len = min(sg_remaining, max_std_len - std->len);
+
+                       if (is_out)
+                               memcpy(bounce, orig, len);
+
+                       std->len += len;
+                       std->ntds_remaining = -1; /* filled in later */
+
+                       bounce += len;
+                       orig += len;
+                       sg_remaining -= len;
+                       remaining -= len;
+               }
+       }
+
+       /*
+        * For each of the new sTDs, map the bounce buffers, create
+        * page lists (if necessary), and fill in std->ntds_remaining.
+        */
+       list_for_each_entry(std, &qset->stds, list_node) {
+               if (std->ntds_remaining != -1)
+                       continue;
+
+               std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len,
+                                              is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               if (dma_mapping_error(&whc->umc->dev, std->dma_addr))
+                       return -EFAULT;
+
+               if (qset_fill_page_list(whc, std, mem_flags) < 0)
+                       return -ENOMEM;
+
+               std->ntds_remaining = ntds--;
+       }
+
+       return 0;
+}
+
+/**
+ * qset_add_urb - add an urb to the qset's queue.
+ *
+ * The URB is chopped into sTDs, one for each qTD that will required.
+ * At least one qTD (and sTD) is required even if the transfer has no
+ * data (e.g., for some control transfers).
+ */
+int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
+       gfp_t mem_flags)
+{
+       struct whc_urb *wurb;
+       int remaining = urb->transfer_buffer_length;
+       u64 transfer_dma = urb->transfer_dma;
+       int ntds_remaining;
+       int ret;
+
+       wurb = kzalloc(sizeof(struct whc_urb), mem_flags);
+       if (wurb == NULL)
+               goto err_no_mem;
+       urb->hcpriv = wurb;
+       wurb->qset = qset;
+       wurb->urb = urb;
+       INIT_WORK(&wurb->dequeue_work, urb_dequeue_work);
+
+       if (urb->num_sgs) {
+               ret = qset_add_urb_sg(whc, qset, urb, mem_flags);
+               if (ret == -EINVAL) {
+                       qset_free_stds(qset, urb);
+                       ret = qset_add_urb_sg_linearize(whc, qset, urb, mem_flags);
+               }
+               if (ret < 0)
+                       goto err_no_mem;
+               return 0;
+       }
+
+       ntds_remaining = DIV_ROUND_UP(remaining, QTD_MAX_XFER_SIZE);
+       if (ntds_remaining == 0)
+               ntds_remaining = 1;
+
+       while (ntds_remaining) {
+               struct whc_std *std;
+               size_t std_len;
+
+               std_len = remaining;
+               if (std_len > QTD_MAX_XFER_SIZE)
+                       std_len = QTD_MAX_XFER_SIZE;
+
+               std = qset_new_std(whc, qset, urb, mem_flags);
+               if (std == NULL)
+                       goto err_no_mem;
+
+               std->dma_addr = transfer_dma;
+               std->len = std_len;
+               std->ntds_remaining = ntds_remaining;
+
+               if (qset_fill_page_list(whc, std, mem_flags) < 0)
+                       goto err_no_mem;
+
+               ntds_remaining--;
+               remaining -= std_len;
+               transfer_dma += std_len;
+       }
+
+       return 0;
+
+err_no_mem:
+       qset_free_stds(qset, urb);
+       return -ENOMEM;
+}
+
+/**
+ * qset_remove_urb - remove an URB from the urb queue.
+ *
+ * The URB is returned to the USB subsystem.
+ */
+void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
+                           struct urb *urb, int status)
+{
+       struct wusbhc *wusbhc = &whc->wusbhc;
+       struct whc_urb *wurb = urb->hcpriv;
+
+       usb_hcd_unlink_urb_from_ep(&wusbhc->usb_hcd, urb);
+       /* Drop the lock as urb->complete() may enqueue another urb. */
+       spin_unlock(&whc->lock);
+       wusbhc_giveback_urb(wusbhc, urb, status);
+       spin_lock(&whc->lock);
+
+       kfree(wurb);
+}
+
+/**
+ * get_urb_status_from_qtd - get the completed urb status from qTD status
+ * @urb:    completed urb
+ * @status: qTD status
+ */
+static int get_urb_status_from_qtd(struct urb *urb, u32 status)
+{
+       if (status & QTD_STS_HALTED) {
+               if (status & QTD_STS_DBE)
+                       return usb_pipein(urb->pipe) ? -ENOSR : -ECOMM;
+               else if (status & QTD_STS_BABBLE)
+                       return -EOVERFLOW;
+               else if (status & QTD_STS_RCE)
+                       return -ETIME;
+               return -EPIPE;
+       }
+       if (usb_pipein(urb->pipe)
+           && (urb->transfer_flags & URB_SHORT_NOT_OK)
+           && urb->actual_length < urb->transfer_buffer_length)
+               return -EREMOTEIO;
+       return 0;
+}
+
+/**
+ * process_inactive_qtd - process an inactive (but not halted) qTD.
+ *
+ * Update the urb with the transfer bytes from the qTD, if the urb is
+ * completely transferred or (in the case of an IN only) the LPF is
+ * set, then the transfer is complete and the urb should be returned
+ * to the system.
+ */
+void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
+                                struct whc_qtd *qtd)
+{
+       struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
+       struct urb *urb = std->urb;
+       uint32_t status;
+       bool complete;
+
+       status = le32_to_cpu(qtd->status);
+
+       urb->actual_length += std->len - QTD_STS_TO_LEN(status);
+
+       if (usb_pipein(urb->pipe) && (status & QTD_STS_LAST_PKT))
+               complete = true;
+       else
+               complete = whc_std_last(std);
+
+       qset_remove_qtd(whc, qset);
+       qset_free_std(whc, std);
+
+       /*
+        * Transfers for this URB are complete?  Then return it to the
+        * USB subsystem.
+        */
+       if (complete) {
+               qset_remove_qtds(whc, qset, urb);
+               qset_remove_urb(whc, qset, urb, get_urb_status_from_qtd(urb, status));
+
+               /*
+                * If iAlt isn't valid then the hardware didn't
+                * advance iCur. Adjust the start and end pointers to
+                * match iCur.
+                */
+               if (!(status & QTD_STS_IALT_VALID))
+                       qset->td_start = qset->td_end
+                               = QH_STATUS_TO_ICUR(le16_to_cpu(qset->qh.status));
+               qset->pause_after_urb = NULL;
+       }
+}
+
+/**
+ * process_halted_qtd - process a qset with a halted qtd
+ *
+ * Remove all the qTDs for the failed URB and return the failed URB to
+ * the USB subsystem.  Then remove all other qTDs so the qset can be
+ * removed.
+ *
+ * FIXME: this is the point where rate adaptation can be done.  If a
+ * transfer failed because it exceeded the maximum number of retries
+ * then it could be reactivated with a slower rate without having to
+ * remove the qset.
+ */
+void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
+                              struct whc_qtd *qtd)
+{
+       struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
+       struct urb *urb = std->urb;
+       int urb_status;
+
+       urb_status = get_urb_status_from_qtd(urb, le32_to_cpu(qtd->status));
+
+       qset_remove_qtds(whc, qset, urb);
+       qset_remove_urb(whc, qset, urb, urb_status);
+
+       list_for_each_entry(std, &qset->stds, list_node) {
+               if (qset->ntds == 0)
+                       break;
+               qset_remove_qtd(whc, qset);
+               std->qtd = NULL;
+       }
+
+       qset->remove = 1;
+}
+
+void qset_free(struct whc *whc, struct whc_qset *qset)
+{
+       dma_pool_free(whc->qset_pool, qset, qset->qset_dma);
+}
+
+/**
+ * qset_delete - wait for a qset to be unused, then free it.
+ */
+void qset_delete(struct whc *whc, struct whc_qset *qset)
+{
+       wait_for_completion(&qset->remove_complete);
+       qset_free(whc, qset);
+}
diff --git a/drivers/staging/wusbcore/host/whci/whcd.h b/drivers/staging/wusbcore/host/whci/whcd.h
new file mode 100644 (file)
index 0000000..a442a25
--- /dev/null
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) private header.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#ifndef __WHCD_H
+#define __WHCD_H
+
+#include <linux/workqueue.h>
+
+#include "../../../uwb/include/whci.h"
+#include "../../../uwb/include/umc.h"
+#include "whci-hc.h"
+
+/* Generic command timeout. */
+#define WHC_GENCMD_TIMEOUT_MS 100
+
+struct whc_dbg;
+
+struct whc {
+       struct wusbhc wusbhc;
+       struct umc_dev *umc;
+
+       resource_size_t base_phys;
+       void __iomem *base;
+       int irq;
+
+       u8 n_devices;
+       u8 n_keys;
+       u8 n_mmc_ies;
+
+       u64 *pz_list;
+       struct dn_buf_entry *dn_buf;
+       struct di_buf_entry *di_buf;
+       dma_addr_t pz_list_dma;
+       dma_addr_t dn_buf_dma;
+       dma_addr_t di_buf_dma;
+
+       spinlock_t   lock;
+       struct mutex mutex;
+
+       void *            gen_cmd_buf;
+       dma_addr_t        gen_cmd_buf_dma;
+       wait_queue_head_t cmd_wq;
+
+       struct workqueue_struct *workqueue;
+       struct work_struct       dn_work;
+
+       struct dma_pool *qset_pool;
+
+       struct list_head async_list;
+       struct list_head async_removed_list;
+       wait_queue_head_t async_list_wq;
+       struct work_struct async_work;
+
+       struct list_head periodic_list[5];
+       struct list_head periodic_removed_list;
+       wait_queue_head_t periodic_list_wq;
+       struct work_struct periodic_work;
+
+       struct whc_dbg *dbg;
+};
+
+#define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc))
+
+/**
+ * struct whc_std - a software TD.
+ * @urb: the URB this sTD is for.
+ * @offset: start of the URB's data for this TD.
+ * @len: the length of data in the associated TD.
+ * @ntds_remaining: number of TDs (starting from this one) in this transfer.
+ *
+ * @bounce_buf: a bounce buffer if the std was from an urb with a sg
+ * list that could not be mapped to qTDs directly.
+ * @bounce_sg: the first scatterlist element bounce_buf is for.
+ * @bounce_offset: the offset into bounce_sg for the start of bounce_buf.
+ *
+ * Queued URBs may require more TDs than are available in a qset so we
+ * use a list of these "software TDs" (sTDs) to hold per-TD data.
+ */
+struct whc_std {
+       struct urb *urb;
+       size_t len;
+       int    ntds_remaining;
+       struct whc_qtd *qtd;
+
+       struct list_head list_node;
+       int num_pointers;
+       dma_addr_t dma_addr;
+       struct whc_page_list_entry *pl_virt;
+
+       void *bounce_buf;
+       struct scatterlist *bounce_sg;
+       unsigned bounce_offset;
+};
+
+/**
+ * struct whc_urb - per URB host controller structure.
+ * @urb: the URB this struct is for.
+ * @qset: the qset associated to the URB.
+ * @dequeue_work: the work to remove the URB when dequeued.
+ * @is_async: the URB belongs to async sheduler or not.
+ * @status: the status to be returned when calling wusbhc_giveback_urb.
+ */
+struct whc_urb {
+       struct urb *urb;
+       struct whc_qset *qset;
+       struct work_struct dequeue_work;
+       bool is_async;
+       int status;
+};
+
+/**
+ * whc_std_last - is this sTD the URB's last?
+ * @std: the sTD to check.
+ */
+static inline bool whc_std_last(struct whc_std *std)
+{
+       return std->ntds_remaining <= 1;
+}
+
+enum whc_update {
+       WHC_UPDATE_ADDED   = 0x01,
+       WHC_UPDATE_REMOVED = 0x02,
+       WHC_UPDATE_UPDATED = 0x04,
+};
+
+/* init.c */
+int whc_init(struct whc *whc);
+void whc_clean_up(struct whc *whc);
+
+/* hw.c */
+void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val);
+int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len);
+void whc_hw_error(struct whc *whc, const char *reason);
+
+/* wusb.c */
+int whc_wusbhc_start(struct wusbhc *wusbhc);
+void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay);
+int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+                 u8 handle, struct wuie_hdr *wuie);
+int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
+int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm);
+int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
+int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots);
+int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+               const void *ptk, size_t key_size);
+int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
+               const void *gtk, size_t key_size);
+int whc_set_cluster_id(struct whc *whc, u8 bcid);
+
+/* int.c */
+irqreturn_t whc_int_handler(struct usb_hcd *hcd);
+void whc_dn_work(struct work_struct *work);
+
+/* asl.c */
+void asl_start(struct whc *whc);
+void asl_stop(struct whc *whc);
+int  asl_init(struct whc *whc);
+void asl_clean_up(struct whc *whc);
+int  asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
+int  asl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
+void asl_qset_delete(struct whc *whc, struct whc_qset *qset);
+void scan_async_work(struct work_struct *work);
+
+/* pzl.c */
+int  pzl_init(struct whc *whc);
+void pzl_clean_up(struct whc *whc);
+void pzl_start(struct whc *whc);
+void pzl_stop(struct whc *whc);
+int  pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
+int  pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
+void pzl_qset_delete(struct whc *whc, struct whc_qset *qset);
+void scan_periodic_work(struct work_struct *work);
+
+/* qset.c */
+struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags);
+void qset_free(struct whc *whc, struct whc_qset *qset);
+struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags);
+void qset_delete(struct whc *whc, struct whc_qset *qset);
+void qset_clear(struct whc *whc, struct whc_qset *qset);
+void qset_reset(struct whc *whc, struct whc_qset *qset);
+int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
+                gfp_t mem_flags);
+void qset_free_std(struct whc *whc, struct whc_std *std);
+void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
+                           struct urb *urb, int status);
+void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
+                              struct whc_qtd *qtd);
+void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
+                                struct whc_qtd *qtd);
+enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset);
+void qset_remove_complete(struct whc *whc, struct whc_qset *qset);
+void pzl_update(struct whc *whc, uint32_t wusbcmd);
+void asl_update(struct whc *whc, uint32_t wusbcmd);
+
+/* debug.c */
+void whc_dbg_init(struct whc *whc);
+void whc_dbg_clean_up(struct whc *whc);
+
+#endif /* #ifndef __WHCD_H */
diff --git a/drivers/staging/wusbcore/host/whci/whci-hc.h b/drivers/staging/wusbcore/host/whci/whci-hc.h
new file mode 100644 (file)
index 0000000..5a86a57
--- /dev/null
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) data structures.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#ifndef _WHCI_WHCI_HC_H
+#define _WHCI_WHCI_HC_H
+
+#include <linux/list.h>
+
+/**
+ * WHCI_PAGE_SIZE - page size use by WHCI
+ *
+ * WHCI assumes that host system uses pages of 4096 octets.
+ */
+#define WHCI_PAGE_SIZE 4096
+
+
+/**
+ * QTD_MAX_TXFER_SIZE - max number of bytes to transfer with a single
+ * qtd.
+ *
+ * This is 2^20 - 1.
+ */
+#define QTD_MAX_XFER_SIZE 1048575
+
+
+/**
+ * struct whc_qtd - Queue Element Transfer Descriptors (qTD)
+ *
+ * This describes the data for a bulk, control or interrupt transfer.
+ *
+ * [WHCI] section 3.2.4
+ */
+struct whc_qtd {
+       __le32 status; /*< remaining transfer len and transfer status */
+       __le32 options;
+       __le64 page_list_ptr; /*< physical pointer to data buffer page list*/
+       __u8   setup[8];      /*< setup data for control transfers */
+} __attribute__((packed));
+
+#define QTD_STS_ACTIVE     (1 << 31)  /* enable execution of transaction */
+#define QTD_STS_HALTED     (1 << 30)  /* transfer halted */
+#define QTD_STS_DBE        (1 << 29)  /* data buffer error */
+#define QTD_STS_BABBLE     (1 << 28)  /* babble detected */
+#define QTD_STS_RCE        (1 << 27)  /* retry count exceeded */
+#define QTD_STS_LAST_PKT   (1 << 26)  /* set Last Packet Flag in WUSB header */
+#define QTD_STS_INACTIVE   (1 << 25)  /* queue set is marked inactive */
+#define QTD_STS_IALT_VALID (1 << 23)                          /* iAlt field is valid */
+#define QTD_STS_IALT(i)    (QTD_STS_IALT_VALID | ((i) << 20)) /* iAlt field */
+#define QTD_STS_LEN(l)     ((l) << 0) /* transfer length */
+#define QTD_STS_TO_LEN(s)  ((s) & 0x000fffff)
+
+#define QTD_OPT_IOC      (1 << 1) /* page_list_ptr points to buffer directly */
+#define QTD_OPT_SMALL    (1 << 0) /* interrupt on complete */
+
+/**
+ * struct whc_itd - Isochronous Queue Element Transfer Descriptors (iTD)
+ *
+ * This describes the data and other parameters for an isochronous
+ * transfer.
+ *
+ * [WHCI] section 3.2.5
+ */
+struct whc_itd {
+       __le16 presentation_time;    /*< presentation time for OUT transfers */
+       __u8   num_segments;         /*< number of data segments in segment list */
+       __u8   status;               /*< command execution status */
+       __le32 options;              /*< misc transfer options */
+       __le64 page_list_ptr;        /*< physical pointer to data buffer page list */
+       __le64 seg_list_ptr;         /*< physical pointer to segment list */
+} __attribute__((packed));
+
+#define ITD_STS_ACTIVE   (1 << 7) /* enable execution of transaction */
+#define ITD_STS_DBE      (1 << 5) /* data buffer error */
+#define ITD_STS_BABBLE   (1 << 4) /* babble detected */
+#define ITD_STS_INACTIVE (1 << 1) /* queue set is marked inactive */
+
+#define ITD_OPT_IOC      (1 << 1) /* interrupt on complete */
+#define ITD_OPT_SMALL    (1 << 0) /* page_list_ptr points to buffer directly */
+
+/**
+ * Page list entry.
+ *
+ * A TD's page list must contain sufficient page list entries for the
+ * total data length in the TD.
+ *
+ * [WHCI] section 3.2.4.3
+ */
+struct whc_page_list_entry {
+       __le64 buf_ptr; /*< physical pointer to buffer */
+} __attribute__((packed));
+
+/**
+ * struct whc_seg_list_entry - Segment list entry.
+ *
+ * Describes a portion of the data buffer described in the containing
+ * qTD's page list.
+ *
+ * seg_ptr = qtd->page_list_ptr[qtd->seg_list_ptr[seg].idx].buf_ptr
+ *           + qtd->seg_list_ptr[seg].offset;
+ *
+ * Segments can't cross page boundries.
+ *
+ * [WHCI] section 3.2.5.5
+ */
+struct whc_seg_list_entry {
+       __le16 len;    /*< segment length */
+       __u8   idx;    /*< index into page list */
+       __u8   status; /*< segment status */
+       __le16 offset; /*< 12 bit offset into page */
+} __attribute__((packed));
+
+/**
+ * struct whc_qhead - endpoint and status information for a qset.
+ *
+ * [WHCI] section 3.2.6
+ */
+struct whc_qhead {
+       __le64 link; /*< next qset in list */
+       __le32 info1;
+       __le32 info2;
+       __le32 info3;
+       __le16 status;
+       __le16 err_count;  /*< transaction error count */
+       __le32 cur_window;
+       __le32 scratch[3]; /*< h/w scratch area */
+       union {
+               struct whc_qtd qtd;
+               struct whc_itd itd;
+       } overlay;
+} __attribute__((packed));
+
+#define QH_LINK_PTR_MASK (~0x03Full)
+#define QH_LINK_PTR(ptr) ((ptr) & QH_LINK_PTR_MASK)
+#define QH_LINK_IQS      (1 << 4) /* isochronous queue set */
+#define QH_LINK_NTDS(n)  (((n) - 1) << 1) /* number of TDs in queue set */
+#define QH_LINK_T        (1 << 0) /* last queue set in periodic schedule list */
+
+#define QH_INFO1_EP(e)           ((e) << 0)  /* endpoint number */
+#define QH_INFO1_DIR_IN          (1 << 4)    /* IN transfer */
+#define QH_INFO1_DIR_OUT         (0 << 4)    /* OUT transfer */
+#define QH_INFO1_TR_TYPE_CTRL    (0x0 << 5)  /* control transfer */
+#define QH_INFO1_TR_TYPE_ISOC    (0x1 << 5)  /* isochronous transfer */
+#define QH_INFO1_TR_TYPE_BULK    (0x2 << 5)  /* bulk transfer */
+#define QH_INFO1_TR_TYPE_INT     (0x3 << 5)  /* interrupt */
+#define QH_INFO1_TR_TYPE_LP_INT  (0x7 << 5)  /* low power interrupt */
+#define QH_INFO1_DEV_INFO_IDX(i) ((i) << 8)  /* index into device info buffer */
+#define QH_INFO1_SET_INACTIVE    (1 << 15)   /* set inactive after transfer */
+#define QH_INFO1_MAX_PKT_LEN(l)  ((l) << 16) /* maximum packet length */
+
+#define QH_INFO2_BURST(b)        ((b) << 0)  /* maximum burst length */
+#define QH_INFO2_DBP(p)          ((p) << 5)  /* data burst policy (see [WUSB] table 5-7) */
+#define QH_INFO2_MAX_COUNT(c)    ((c) << 8)  /* max isoc/int pkts per zone */
+#define QH_INFO2_RQS             (1 << 15)   /* reactivate queue set */
+#define QH_INFO2_MAX_RETRY(r)    ((r) << 16) /* maximum transaction retries */
+#define QH_INFO2_MAX_SEQ(s)      ((s) << 20) /* maximum sequence number */
+#define QH_INFO3_MAX_DELAY(d)    ((d) << 0)  /* maximum stream delay in 125 us units (isoc only) */
+#define QH_INFO3_INTERVAL(i)     ((i) << 16) /* segment interval in 125 us units (isoc only) */
+
+#define QH_INFO3_TX_RATE(r)      ((r) << 24) /* PHY rate (see [ECMA-368] section 10.3.1.1) */
+#define QH_INFO3_TX_PWR(p)       ((p) << 29) /* transmit power (see [WUSB] section 5.2.1.2) */
+
+#define QH_STATUS_FLOW_CTRL      (1 << 15)
+#define QH_STATUS_ICUR(i)        ((i) << 5)
+#define QH_STATUS_TO_ICUR(s)     (((s) >> 5) & 0x7)
+#define QH_STATUS_SEQ_MASK       0x1f
+
+/**
+ * usb_pipe_to_qh_type - USB core pipe type to QH transfer type
+ *
+ * Returns the QH type field for a USB core pipe type.
+ */
+static inline unsigned usb_pipe_to_qh_type(unsigned pipe)
+{
+       static const unsigned type[] = {
+               [PIPE_ISOCHRONOUS] = QH_INFO1_TR_TYPE_ISOC,
+               [PIPE_INTERRUPT]   = QH_INFO1_TR_TYPE_INT,
+               [PIPE_CONTROL]     = QH_INFO1_TR_TYPE_CTRL,
+               [PIPE_BULK]        = QH_INFO1_TR_TYPE_BULK,
+       };
+       return type[usb_pipetype(pipe)];
+}
+
+/**
+ * Maxiumum number of TDs in a qset.
+ */
+#define WHCI_QSET_TD_MAX 8
+
+/**
+ * struct whc_qset - WUSB data transfers to a specific endpoint
+ * @qh: the QHead of this qset
+ * @qtd: up to 8 qTDs (for qsets for control, bulk and interrupt
+ * transfers)
+ * @itd: up to 8 iTDs (for qsets for isochronous transfers)
+ * @qset_dma: DMA address for this qset
+ * @whc: WHCI HC this qset is for
+ * @ep: endpoint
+ * @stds: list of sTDs queued to this qset
+ * @ntds: number of qTDs queued (not necessarily the same as nTDs
+ * field in the QH)
+ * @td_start: index of the first qTD in the list
+ * @td_end: index of next free qTD in the list (provided
+ *          ntds < WHCI_QSET_TD_MAX)
+ *
+ * Queue Sets (qsets) are added to the asynchronous schedule list
+ * (ASL) or the periodic zone list (PZL).
+ *
+ * qsets may contain up to 8 TDs (either qTDs or iTDs as appropriate).
+ * Each TD may refer to at most 1 MiB of data. If a single transfer
+ * has > 8MiB of data, TDs can be reused as they are completed since
+ * the TD list is used as a circular buffer.  Similarly, several
+ * (smaller) transfers may be queued in a qset.
+ *
+ * WHCI controllers may cache portions of the qsets in the ASL and
+ * PZL, requiring the WHCD to inform the WHC that the lists have been
+ * updated (fields changed or qsets inserted or removed).  For safe
+ * insertion and removal of qsets from the lists the schedule must be
+ * stopped to avoid races in updating the QH link pointers.
+ *
+ * Since the HC is free to execute qsets in any order, all transfers
+ * to an endpoint should use the same qset to ensure transfers are
+ * executed in the order they're submitted.
+ *
+ * [WHCI] section 3.2.3
+ */
+struct whc_qset {
+       struct whc_qhead qh;
+       union {
+               struct whc_qtd qtd[WHCI_QSET_TD_MAX];
+               struct whc_itd itd[WHCI_QSET_TD_MAX];
+       };
+
+       /* private data for WHCD */
+       dma_addr_t qset_dma;
+       struct whc *whc;
+       struct usb_host_endpoint *ep;
+       struct list_head stds;
+       int ntds;
+       int td_start;
+       int td_end;
+       struct list_head list_node;
+       unsigned in_sw_list:1;
+       unsigned in_hw_list:1;
+       unsigned remove:1;
+       unsigned reset:1;
+       struct urb *pause_after_urb;
+       struct completion remove_complete;
+       uint16_t max_packet;
+       uint8_t max_burst;
+       uint8_t max_seq;
+};
+
+static inline void whc_qset_set_link_ptr(u64 *ptr, u64 target)
+{
+       if (target)
+               *ptr = (*ptr & ~(QH_LINK_PTR_MASK | QH_LINK_T)) | QH_LINK_PTR(target);
+       else
+               *ptr = QH_LINK_T;
+}
+
+/**
+ * struct di_buf_entry - Device Information (DI) buffer entry.
+ *
+ * There's one of these per connected device.
+ */
+struct di_buf_entry {
+       __le32 availability_info[8]; /*< MAS availability information, one MAS per bit */
+       __le32 addr_sec_info;        /*< addressing and security info */
+       __le32 reserved[7];
+} __attribute__((packed));
+
+#define WHC_DI_SECURE           (1 << 31)
+#define WHC_DI_DISABLE          (1 << 30)
+#define WHC_DI_KEY_IDX(k)       ((k) << 8)
+#define WHC_DI_KEY_IDX_MASK     0x0000ff00
+#define WHC_DI_DEV_ADDR(a)      ((a) << 0)
+#define WHC_DI_DEV_ADDR_MASK    0x000000ff
+
+/**
+ * struct dn_buf_entry - Device Notification (DN) buffer entry.
+ *
+ * [WHCI] section 3.2.8
+ */
+struct dn_buf_entry {
+       __u8   msg_size;    /*< number of octets of valid DN data */
+       __u8   reserved1;
+       __u8   src_addr;    /*< source address */
+       __u8   status;      /*< buffer entry status */
+       __le32 tkid;        /*< TKID for source device, valid if secure bit is set */
+       __u8   dn_data[56]; /*< up to 56 octets of DN data */
+} __attribute__((packed));
+
+#define WHC_DN_STATUS_VALID  (1 << 7) /* buffer entry is valid */
+#define WHC_DN_STATUS_SECURE (1 << 6) /* notification received using secure frame */
+
+#define WHC_N_DN_ENTRIES (4096 / sizeof(struct dn_buf_entry))
+
+/* The Add MMC IE WUSB Generic Command may take up to 256 bytes of
+   data. [WHCI] section 2.4.7. */
+#define WHC_GEN_CMD_DATA_LEN 256
+
+/*
+ * HC registers.
+ *
+ * [WHCI] section 2.4
+ */
+
+#define WHCIVERSION          0x00
+
+#define WHCSPARAMS           0x04
+#  define WHCSPARAMS_TO_N_MMC_IES(p) (((p) >> 16) & 0xff)
+#  define WHCSPARAMS_TO_N_KEYS(p)    (((p) >> 8) & 0xff)
+#  define WHCSPARAMS_TO_N_DEVICES(p) (((p) >> 0) & 0x7f)
+
+#define WUSBCMD              0x08
+#  define WUSBCMD_BCID(b)            ((b) << 16)
+#  define WUSBCMD_BCID_MASK          (0xff << 16)
+#  define WUSBCMD_ASYNC_QSET_RM      (1 << 12)
+#  define WUSBCMD_PERIODIC_QSET_RM   (1 << 11)
+#  define WUSBCMD_WUSBSI(s)          ((s) << 8)
+#  define WUSBCMD_WUSBSI_MASK        (0x7 << 8)
+#  define WUSBCMD_ASYNC_SYNCED_DB    (1 << 7)
+#  define WUSBCMD_PERIODIC_SYNCED_DB (1 << 6)
+#  define WUSBCMD_ASYNC_UPDATED      (1 << 5)
+#  define WUSBCMD_PERIODIC_UPDATED   (1 << 4)
+#  define WUSBCMD_ASYNC_EN           (1 << 3)
+#  define WUSBCMD_PERIODIC_EN        (1 << 2)
+#  define WUSBCMD_WHCRESET           (1 << 1)
+#  define WUSBCMD_RUN                (1 << 0)
+
+#define WUSBSTS              0x0c
+#  define WUSBSTS_ASYNC_SCHED             (1 << 15)
+#  define WUSBSTS_PERIODIC_SCHED          (1 << 14)
+#  define WUSBSTS_DNTS_SCHED              (1 << 13)
+#  define WUSBSTS_HCHALTED                (1 << 12)
+#  define WUSBSTS_GEN_CMD_DONE            (1 << 9)
+#  define WUSBSTS_CHAN_TIME_ROLLOVER      (1 << 8)
+#  define WUSBSTS_DNTS_OVERFLOW           (1 << 7)
+#  define WUSBSTS_BPST_ADJUSTMENT_CHANGED (1 << 6)
+#  define WUSBSTS_HOST_ERR                (1 << 5)
+#  define WUSBSTS_ASYNC_SCHED_SYNCED      (1 << 4)
+#  define WUSBSTS_PERIODIC_SCHED_SYNCED   (1 << 3)
+#  define WUSBSTS_DNTS_INT                (1 << 2)
+#  define WUSBSTS_ERR_INT                 (1 << 1)
+#  define WUSBSTS_INT                     (1 << 0)
+#  define WUSBSTS_INT_MASK                0x3ff
+
+#define WUSBINTR             0x10
+#  define WUSBINTR_GEN_CMD_DONE             (1 << 9)
+#  define WUSBINTR_CHAN_TIME_ROLLOVER       (1 << 8)
+#  define WUSBINTR_DNTS_OVERFLOW            (1 << 7)
+#  define WUSBINTR_BPST_ADJUSTMENT_CHANGED  (1 << 6)
+#  define WUSBINTR_HOST_ERR                 (1 << 5)
+#  define WUSBINTR_ASYNC_SCHED_SYNCED       (1 << 4)
+#  define WUSBINTR_PERIODIC_SCHED_SYNCED    (1 << 3)
+#  define WUSBINTR_DNTS_INT                 (1 << 2)
+#  define WUSBINTR_ERR_INT                  (1 << 1)
+#  define WUSBINTR_INT                      (1 << 0)
+#  define WUSBINTR_ALL 0x3ff
+
+#define WUSBGENCMDSTS        0x14
+#  define WUSBGENCMDSTS_ACTIVE (1 << 31)
+#  define WUSBGENCMDSTS_ERROR  (1 << 24)
+#  define WUSBGENCMDSTS_IOC    (1 << 23)
+#  define WUSBGENCMDSTS_MMCIE_ADD 0x01
+#  define WUSBGENCMDSTS_MMCIE_RM  0x02
+#  define WUSBGENCMDSTS_SET_MAS   0x03
+#  define WUSBGENCMDSTS_CHAN_STOP 0x04
+#  define WUSBGENCMDSTS_RWP_EN    0x05
+
+#define WUSBGENCMDPARAMS     0x18
+#define WUSBGENADDR          0x20
+#define WUSBASYNCLISTADDR    0x28
+#define WUSBDNTSBUFADDR      0x30
+#define WUSBDEVICEINFOADDR   0x38
+
+#define WUSBSETSECKEYCMD     0x40
+#  define WUSBSETSECKEYCMD_SET    (1 << 31)
+#  define WUSBSETSECKEYCMD_ERASE  (1 << 30)
+#  define WUSBSETSECKEYCMD_GTK    (1 << 8)
+#  define WUSBSETSECKEYCMD_IDX(i) ((i) << 0)
+
+#define WUSBTKID             0x44
+#define WUSBSECKEY           0x48
+#define WUSBPERIODICLISTBASE 0x58
+#define WUSBMASINDEX         0x60
+
+#define WUSBDNTSCTRL         0x64
+#  define WUSBDNTSCTRL_ACTIVE      (1 << 31)
+#  define WUSBDNTSCTRL_INTERVAL(i) ((i) << 8)
+#  define WUSBDNTSCTRL_SLOTS(s)    ((s) << 0)
+
+#define WUSBTIME             0x68
+#  define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff
+
+#define WUSBBPST             0x6c
+#define WUSBDIBUPDATED       0x70
+
+#endif /* #ifndef _WHCI_WHCI_HC_H */
diff --git a/drivers/staging/wusbcore/host/whci/wusb.c b/drivers/staging/wusbcore/host/whci/wusb.c
new file mode 100644 (file)
index 0000000..6d0068a
--- /dev/null
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless Host Controller (WHC) WUSB operations.
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+
+#include "../../../uwb/include/umc.h"
+#include "../../wusbhc.h"
+
+#include "whcd.h"
+
+static int whc_update_di(struct whc *whc, int idx)
+{
+       int offset = idx / 32;
+       u32 bit = 1 << (idx % 32);
+
+       le_writel(bit, whc->base + WUSBDIBUPDATED + offset);
+
+       return whci_wait_for(&whc->umc->dev,
+                            whc->base + WUSBDIBUPDATED + offset, bit, 0,
+                            100, "DI update");
+}
+
+/*
+ * WHCI starts MMCs based on there being a valid GTK so these need
+ * only start/stop the asynchronous and periodic schedules and send a
+ * channel stop command.
+ */
+
+int whc_wusbhc_start(struct wusbhc *wusbhc)
+{
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+
+       asl_start(whc);
+       pzl_start(whc);
+
+       return 0;
+}
+
+void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay)
+{
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       u32 stop_time, now_time;
+       int ret;
+
+       pzl_stop(whc);
+       asl_stop(whc);
+
+       now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK;
+       stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff;
+       ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0);
+       if (ret == 0)
+               msleep(delay);
+}
+
+int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+                 u8 handle, struct wuie_hdr *wuie)
+{
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       u32 params;
+
+       params = (interval << 24)
+               | (repeat_cnt << 16)
+               | (wuie->bLength << 8)
+               | handle;
+
+       return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength);
+}
+
+int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
+{
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       u32 params;
+
+       params = handle;
+
+       return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0);
+}
+
+int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm)
+{
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+
+       if (stream_index >= 0)
+               whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index));
+
+       return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm));
+}
+
+int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       int idx = wusb_dev->port_idx;
+       struct di_buf_entry *di = &whc->di_buf[idx];
+       int ret;
+
+       mutex_lock(&whc->mutex);
+
+       uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability);
+       di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK);
+       di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr);
+
+       ret = whc_update_di(whc, idx);
+
+       mutex_unlock(&whc->mutex);
+
+       return ret;
+}
+
+/*
+ * Set the number of Device Notification Time Slots (DNTS) and enable
+ * device notifications.
+ */
+int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
+{
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       u32 dntsctrl;
+
+       dntsctrl = WUSBDNTSCTRL_ACTIVE
+               | WUSBDNTSCTRL_INTERVAL(interval)
+               | WUSBDNTSCTRL_SLOTS(slots);
+
+       le_writel(dntsctrl, whc->base + WUSBDNTSCTRL);
+
+       return 0;
+}
+
+static int whc_set_key(struct whc *whc, u8 key_index, uint32_t tkid,
+                      const void *key, size_t key_size, bool is_gtk)
+{
+       uint32_t setkeycmd;
+       uint32_t seckey[4];
+       int i;
+       int ret;
+
+       memcpy(seckey, key, key_size);
+       setkeycmd = WUSBSETSECKEYCMD_SET | WUSBSETSECKEYCMD_IDX(key_index);
+       if (is_gtk)
+               setkeycmd |= WUSBSETSECKEYCMD_GTK;
+
+       le_writel(tkid, whc->base + WUSBTKID);
+       for (i = 0; i < 4; i++)
+               le_writel(seckey[i], whc->base + WUSBSECKEY + 4*i);
+       le_writel(setkeycmd, whc->base + WUSBSETSECKEYCMD);
+
+       ret = whci_wait_for(&whc->umc->dev, whc->base + WUSBSETSECKEYCMD,
+                           WUSBSETSECKEYCMD_SET, 0, 100, "set key");
+
+       return ret;
+}
+
+/**
+ * whc_set_ptk - set the PTK to use for a device.
+ *
+ * The index into the key table for this PTK is the same as the
+ * device's port index.
+ */
+int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
+               const void *ptk, size_t key_size)
+{
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       struct di_buf_entry *di = &whc->di_buf[port_idx];
+       int ret;
+
+       mutex_lock(&whc->mutex);
+
+       if (ptk) {
+               ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false);
+               if (ret)
+                       goto out;
+
+               di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK;
+               di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx);
+       } else
+               di->addr_sec_info &= ~WHC_DI_SECURE;
+
+       ret = whc_update_di(whc, port_idx);
+out:
+       mutex_unlock(&whc->mutex);
+       return ret;
+}
+
+/**
+ * whc_set_gtk - set the GTK for subsequent broadcast packets
+ *
+ * The GTK is stored in the last entry in the key table (the previous
+ * N_DEVICES entries are for the per-device PTKs).
+ */
+int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
+               const void *gtk, size_t key_size)
+{
+       struct whc *whc = wusbhc_to_whc(wusbhc);
+       int ret;
+
+       mutex_lock(&whc->mutex);
+
+       ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true);
+
+       mutex_unlock(&whc->mutex);
+
+       return ret;
+}
+
+int whc_set_cluster_id(struct whc *whc, u8 bcid)
+{
+       whc_write_wusbcmd(whc, WUSBCMD_BCID_MASK, WUSBCMD_BCID(bcid));
+       return 0;
+}
diff --git a/drivers/staging/wusbcore/include/association.h b/drivers/staging/wusbcore/include/association.h
new file mode 100644 (file)
index 0000000..d7f3cb9
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB - Cable Based Association
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ */
+#ifndef __LINUX_USB_ASSOCIATION_H
+#define __LINUX_USB_ASSOCIATION_H
+
+
+/*
+ * Association attributes
+ *
+ * Association Models Supplement to WUSB 1.0 T[3-1]
+ *
+ * Each field in the structures has it's ID, it's length and then the
+ * value. This is the actual definition of the field's ID and its
+ * length.
+ */
+struct wusb_am_attr {
+       __u8 id;
+       __u8 len;
+};
+
+/* Different fields defined by the spec */
+#define WUSB_AR_AssociationTypeId      { .id = cpu_to_le16(0x0000), .len = cpu_to_le16(2) }
+#define WUSB_AR_AssociationSubTypeId   { .id = cpu_to_le16(0x0001), .len = cpu_to_le16(2) }
+#define WUSB_AR_Length                 { .id = cpu_to_le16(0x0002), .len = cpu_to_le16(4) }
+#define WUSB_AR_AssociationStatus      { .id = cpu_to_le16(0x0004), .len = cpu_to_le16(4) }
+#define WUSB_AR_LangID                 { .id = cpu_to_le16(0x0008), .len = cpu_to_le16(2) }
+#define WUSB_AR_DeviceFriendlyName     { .id = cpu_to_le16(0x000b), .len = cpu_to_le16(64) } /* max */
+#define WUSB_AR_HostFriendlyName       { .id = cpu_to_le16(0x000c), .len = cpu_to_le16(64) } /* max */
+#define WUSB_AR_CHID                   { .id = cpu_to_le16(0x1000), .len = cpu_to_le16(16) }
+#define WUSB_AR_CDID                   { .id = cpu_to_le16(0x1001), .len = cpu_to_le16(16) }
+#define WUSB_AR_ConnectionContext      { .id = cpu_to_le16(0x1002), .len = cpu_to_le16(48) }
+#define WUSB_AR_BandGroups             { .id = cpu_to_le16(0x1004), .len = cpu_to_le16(2) }
+
+/* CBAF Control Requests (AMS1.0[T4-1] */
+enum {
+       CBAF_REQ_GET_ASSOCIATION_INFORMATION = 0x01,
+       CBAF_REQ_GET_ASSOCIATION_REQUEST,
+       CBAF_REQ_SET_ASSOCIATION_RESPONSE
+};
+
+/*
+ * CBAF USB-interface defitions
+ *
+ * No altsettings, one optional interrupt endpoint.
+ */
+enum {
+       CBAF_IFACECLASS    = 0xef,
+       CBAF_IFACESUBCLASS = 0x03,
+       CBAF_IFACEPROTOCOL = 0x01,
+};
+
+/* Association Information (AMS1.0[T4-3]) */
+struct wusb_cbaf_assoc_info {
+       __le16 Length;
+       __u8 NumAssociationRequests;
+       __le16 Flags;
+       __u8 AssociationRequestsArray[];
+} __attribute__((packed));
+
+/* Association Request (AMS1.0[T4-4]) */
+struct wusb_cbaf_assoc_request {
+       __u8 AssociationDataIndex;
+       __u8 Reserved;
+       __le16 AssociationTypeId;
+       __le16 AssociationSubTypeId;
+       __le32 AssociationTypeInfoSize;
+} __attribute__((packed));
+
+enum {
+       AR_TYPE_WUSB                    = 0x0001,
+       AR_TYPE_WUSB_RETRIEVE_HOST_INFO = 0x0000,
+       AR_TYPE_WUSB_ASSOCIATE          = 0x0001,
+};
+
+/* Association Attribute header (AMS1.0[3.8]) */
+struct wusb_cbaf_attr_hdr {
+       __le16 id;
+       __le16 len;
+} __attribute__((packed));
+
+/* Host Info (AMS1.0[T4-7]) (yeah, more headers and fields...) */
+struct wusb_cbaf_host_info {
+       struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
+       __le16 AssociationTypeId;
+       struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
+       __le16 AssociationSubTypeId;
+       struct wusb_cbaf_attr_hdr CHID_hdr;
+       struct wusb_ckhdid CHID;
+       struct wusb_cbaf_attr_hdr LangID_hdr;
+       __le16 LangID;
+       struct wusb_cbaf_attr_hdr HostFriendlyName_hdr;
+       __u8 HostFriendlyName[];
+} __attribute__((packed));
+
+/* Device Info (AMS1.0[T4-8])
+ *
+ * I still don't get this tag'n'header stuff for each goddamn
+ * field...
+ */
+struct wusb_cbaf_device_info {
+       struct wusb_cbaf_attr_hdr Length_hdr;
+       __le32 Length;
+       struct wusb_cbaf_attr_hdr CDID_hdr;
+       struct wusb_ckhdid CDID;
+       struct wusb_cbaf_attr_hdr BandGroups_hdr;
+       __le16 BandGroups;
+       struct wusb_cbaf_attr_hdr LangID_hdr;
+       __le16 LangID;
+       struct wusb_cbaf_attr_hdr DeviceFriendlyName_hdr;
+       __u8 DeviceFriendlyName[];
+} __attribute__((packed));
+
+/* Connection Context; CC_DATA - Success case (AMS1.0[T4-9]) */
+struct wusb_cbaf_cc_data {
+       struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
+       __le16 AssociationTypeId;
+       struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
+       __le16 AssociationSubTypeId;
+       struct wusb_cbaf_attr_hdr Length_hdr;
+       __le32 Length;
+       struct wusb_cbaf_attr_hdr ConnectionContext_hdr;
+       struct wusb_ckhdid CHID;
+       struct wusb_ckhdid CDID;
+       struct wusb_ckhdid CK;
+       struct wusb_cbaf_attr_hdr BandGroups_hdr;
+       __le16 BandGroups;
+} __attribute__((packed));
+
+/* CC_DATA - Failure case (AMS1.0[T4-10]) */
+struct wusb_cbaf_cc_data_fail {
+       struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
+       __le16 AssociationTypeId;
+       struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
+       __le16 AssociationSubTypeId;
+       struct wusb_cbaf_attr_hdr Length_hdr;
+       __le16 Length;
+       struct wusb_cbaf_attr_hdr AssociationStatus_hdr;
+       __u32 AssociationStatus;
+} __attribute__((packed));
+
+#endif /* __LINUX_USB_ASSOCIATION_H */
diff --git a/drivers/staging/wusbcore/include/wusb-wa.h b/drivers/staging/wusbcore/include/wusb-wa.h
new file mode 100644 (file)
index 0000000..64a840b
--- /dev/null
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Wire Adapter constants and structures.
+ *
+ * Copyright (C) 2005-2006 Intel Corporation.
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * FIXME: docs
+ * FIXME: organize properly, group logically
+ *
+ * All the event structures are defined in uwb/spec.h, as they are
+ * common to the WHCI and WUSB radio control interfaces.
+ *
+ * References:
+ *   [WUSB] Wireless Universal Serial Bus Specification, revision 1.0, ch8
+ */
+#ifndef __LINUX_USB_WUSB_WA_H
+#define __LINUX_USB_WUSB_WA_H
+
+/**
+ * Radio Command Request for the Radio Control Interface
+ *
+ * Radio Control Interface command and event codes are the same as
+ * WHCI, and listed in include/linux/uwb.h:UWB_RC_{CMD,EVT}_*
+ */
+enum {
+       WA_EXEC_RC_CMD = 40,    /* Radio Control command Request */
+};
+
+/* Wireless Adapter Requests ([WUSB] table 8-51) */
+enum {
+       WUSB_REQ_ADD_MMC_IE     = 20,
+       WUSB_REQ_REMOVE_MMC_IE  = 21,
+       WUSB_REQ_SET_NUM_DNTS   = 22,
+       WUSB_REQ_SET_CLUSTER_ID = 23,
+       WUSB_REQ_SET_DEV_INFO   = 24,
+       WUSB_REQ_GET_TIME       = 25,
+       WUSB_REQ_SET_STREAM_IDX = 26,
+       WUSB_REQ_SET_WUSB_MAS   = 27,
+       WUSB_REQ_CHAN_STOP      = 28,
+};
+
+
+/* Wireless Adapter WUSB Channel Time types ([WUSB] table 8-52) */
+enum {
+       WUSB_TIME_ADJ   = 0,
+       WUSB_TIME_BPST  = 1,
+       WUSB_TIME_WUSB  = 2,
+};
+
+enum {
+       WA_ENABLE = 0x01,
+       WA_RESET = 0x02,
+       RPIPE_PAUSE = 0x1,
+       RPIPE_STALL = 0x2,
+};
+
+/* Responses from Get Status request ([WUSB] section 8.3.1.6) */
+enum {
+       WA_STATUS_ENABLED = 0x01,
+       WA_STATUS_RESETTING = 0x02
+};
+
+enum rpipe_crs {
+       RPIPE_CRS_CTL = 0x01,
+       RPIPE_CRS_ISO = 0x02,
+       RPIPE_CRS_BULK = 0x04,
+       RPIPE_CRS_INTR = 0x08
+};
+
+/**
+ * RPipe descriptor ([WUSB] section 8.5.2.11)
+ *
+ * FIXME: explain rpipes
+ */
+struct usb_rpipe_descriptor {
+       u8      bLength;
+       u8      bDescriptorType;
+       __le16  wRPipeIndex;
+       __le16  wRequests;
+       __le16  wBlocks;                /* rw if 0 */
+       __le16  wMaxPacketSize;         /* rw */
+       union {
+               u8      dwa_bHSHubAddress;              /* rw: DWA. */
+               u8      hwa_bMaxBurst;                  /* rw: HWA. */
+       };
+       union {
+               u8      dwa_bHSHubPort;         /*  rw: DWA. */
+               u8      hwa_bDeviceInfoIndex;   /*  rw: HWA. */
+       };
+       u8      bSpeed;                 /* rw: xfer rate 'enum uwb_phy_rate' */
+       union {
+               u8 dwa_bDeviceAddress;  /* rw: DWA Target device address. */
+               u8 hwa_reserved;                /* rw: HWA. */
+       };
+       u8      bEndpointAddress;       /* rw: Target EP address */
+       u8      bDataSequence;          /* ro: Current Data sequence */
+       __le32  dwCurrentWindow;        /* ro */
+       u8      bMaxDataSequence;       /* ro?: max supported seq */
+       u8      bInterval;              /* rw:  */
+       u8      bOverTheAirInterval;    /* rw:  */
+       u8      bmAttribute;            /* ro?  */
+       u8      bmCharacteristics;      /* ro? enum rpipe_attr, supported xsactions */
+       u8      bmRetryOptions;         /* rw? */
+       __le16  wNumTransactionErrors;  /* rw */
+} __attribute__ ((packed));
+
+/**
+ * Wire Adapter Notification types ([WUSB] sections 8.4.5 & 8.5.4)
+ *
+ * These are the notifications coming on the notification endpoint of
+ * an HWA and a DWA.
+ */
+enum wa_notif_type {
+       DWA_NOTIF_RWAKE = 0x91,
+       DWA_NOTIF_PORTSTATUS = 0x92,
+       WA_NOTIF_TRANSFER = 0x93,
+       HWA_NOTIF_BPST_ADJ = 0x94,
+       HWA_NOTIF_DN = 0x95,
+};
+
+/**
+ * Wire Adapter notification header
+ *
+ * Notifications coming from a wire adapter use a common header
+ * defined in [WUSB] sections 8.4.5 & 8.5.4.
+ */
+struct wa_notif_hdr {
+       u8 bLength;
+       u8 bNotifyType;                 /* enum wa_notif_type */
+} __packed;
+
+/**
+ * HWA DN Received notification [(WUSB] section 8.5.4.2)
+ *
+ * The DNData is specified in WUSB1.0[7.6]. For each device
+ * notification we received, we just need to dispatch it.
+ *
+ * @dndata:  this is really an array of notifications, but all start
+ *           with the same header.
+ */
+struct hwa_notif_dn {
+       struct wa_notif_hdr hdr;
+       u8 bSourceDeviceAddr;           /* from errata 2005/07 */
+       u8 bmAttributes;
+       struct wusb_dn_hdr dndata[];
+} __packed;
+
+/* [WUSB] section 8.3.3 */
+enum wa_xfer_type {
+       WA_XFER_TYPE_CTL = 0x80,
+       WA_XFER_TYPE_BI = 0x81,         /* bulk/interrupt */
+       WA_XFER_TYPE_ISO = 0x82,
+       WA_XFER_RESULT = 0x83,
+       WA_XFER_ABORT = 0x84,
+       WA_XFER_ISO_PACKET_INFO = 0xA0,
+       WA_XFER_ISO_PACKET_STATUS = 0xA1,
+};
+
+/* [WUSB] section 8.3.3 */
+struct wa_xfer_hdr {
+       u8 bLength;                     /* 0x18 */
+       u8 bRequestType;                /* 0x80 WA_REQUEST_TYPE_CTL */
+       __le16 wRPipe;                  /* RPipe index */
+       __le32 dwTransferID;            /* Host-assigned ID */
+       __le32 dwTransferLength;        /* Length of data to xfer */
+       u8 bTransferSegment;
+} __packed;
+
+struct wa_xfer_ctl {
+       struct wa_xfer_hdr hdr;
+       u8 bmAttribute;
+       __le16 wReserved;
+       struct usb_ctrlrequest baSetupData;
+} __packed;
+
+struct wa_xfer_bi {
+       struct wa_xfer_hdr hdr;
+       u8 bReserved;
+       __le16 wReserved;
+} __packed;
+
+/* [WUSB] section 8.5.5 */
+struct wa_xfer_hwaiso {
+       struct wa_xfer_hdr hdr;
+       u8 bReserved;
+       __le16 wPresentationTime;
+       __le32 dwNumOfPackets;
+} __packed;
+
+struct wa_xfer_packet_info_hwaiso {
+       __le16 wLength;
+       u8 bPacketType;
+       u8 bReserved;
+       __le16 PacketLength[0];
+} __packed;
+
+struct wa_xfer_packet_status_len_hwaiso {
+       __le16 PacketLength;
+       __le16 PacketStatus;
+} __packed;
+
+struct wa_xfer_packet_status_hwaiso {
+       __le16 wLength;
+       u8 bPacketType;
+       u8 bReserved;
+       struct wa_xfer_packet_status_len_hwaiso PacketStatus[0];
+} __packed;
+
+/* [WUSB] section 8.3.3.5 */
+struct wa_xfer_abort {
+       u8 bLength;
+       u8 bRequestType;
+       __le16 wRPipe;                  /* RPipe index */
+       __le32 dwTransferID;            /* Host-assigned ID */
+} __packed;
+
+/**
+ * WA Transfer Complete notification ([WUSB] section 8.3.3.3)
+ *
+ */
+struct wa_notif_xfer {
+       struct wa_notif_hdr hdr;
+       u8 bEndpoint;
+       u8 Reserved;
+} __packed;
+
+/** Transfer result basic codes [WUSB] table 8-15 */
+enum {
+       WA_XFER_STATUS_SUCCESS,
+       WA_XFER_STATUS_HALTED,
+       WA_XFER_STATUS_DATA_BUFFER_ERROR,
+       WA_XFER_STATUS_BABBLE,
+       WA_XFER_RESERVED,
+       WA_XFER_STATUS_NOT_FOUND,
+       WA_XFER_STATUS_INSUFFICIENT_RESOURCE,
+       WA_XFER_STATUS_TRANSACTION_ERROR,
+       WA_XFER_STATUS_ABORTED,
+       WA_XFER_STATUS_RPIPE_NOT_READY,
+       WA_XFER_INVALID_FORMAT,
+       WA_XFER_UNEXPECTED_SEGMENT_NUMBER,
+       WA_XFER_STATUS_RPIPE_TYPE_MISMATCH,
+};
+
+/** [WUSB] section 8.3.3.4 */
+struct wa_xfer_result {
+       struct wa_notif_hdr hdr;
+       __le32 dwTransferID;
+       __le32 dwTransferLength;
+       u8     bTransferSegment;
+       u8     bTransferStatus;
+       __le32 dwNumOfPackets;
+} __packed;
+
+/**
+ * Wire Adapter Class Descriptor ([WUSB] section 8.5.2.7).
+ *
+ * NOTE: u16 fields are read Little Endian from the hardware.
+ *
+ * @bNumPorts is the original max number of devices that the host can
+ *            connect; we might chop this so the stack can handle
+ *            it. In case you need to access it, use wusbhc->ports_max
+ *            if it is a Wireless USB WA.
+ */
+struct usb_wa_descriptor {
+       u8      bLength;
+       u8      bDescriptorType;
+       __le16  bcdWAVersion;
+       u8      bNumPorts;              /* don't use!! */
+       u8      bmAttributes;           /* Reserved == 0 */
+       __le16  wNumRPipes;
+       __le16  wRPipeMaxBlock;
+       u8      bRPipeBlockSize;
+       u8      bPwrOn2PwrGood;
+       u8      bNumMMCIEs;
+       u8      DeviceRemovable;        /* FIXME: in DWA this is up to 16 bytes */
+} __packed;
+
+/**
+ * HWA Device Information Buffer (WUSB1.0[T8.54])
+ */
+struct hwa_dev_info {
+       u8      bmDeviceAvailability[32];       /* FIXME: ignored for now */
+       u8      bDeviceAddress;
+       __le16  wPHYRates;
+       u8      bmDeviceAttribute;
+} __packed;
+
+#endif /* #ifndef __LINUX_USB_WUSB_WA_H */
diff --git a/drivers/staging/wusbcore/include/wusb.h b/drivers/staging/wusbcore/include/wusb.h
new file mode 100644 (file)
index 0000000..09771d1
--- /dev/null
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Standard Definitions
+ * Event Size Tables
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * FIXME: docs
+ * FIXME: organize properly, group logically
+ *
+ * All the event structures are defined in uwb/spec.h, as they are
+ * common to the WHCI and WUSB radio control interfaces.
+ */
+
+#ifndef __WUSB_H__
+#define __WUSB_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/usb/ch9.h>
+#include <linux/param.h>
+#include "../../uwb/include/spec.h"
+
+/**
+ * WUSB Information Element header
+ *
+ * I don't know why, they decided to make it different to the MBOA MAC
+ * IE Header; beats me.
+ */
+struct wuie_hdr {
+       u8 bLength;
+       u8 bIEIdentifier;
+} __attribute__((packed));
+
+enum {
+       WUIE_ID_WCTA = 0x80,
+       WUIE_ID_CONNECTACK,
+       WUIE_ID_HOST_INFO,
+       WUIE_ID_CHANGE_ANNOUNCE,
+       WUIE_ID_DEVICE_DISCONNECT,
+       WUIE_ID_HOST_DISCONNECT,
+       WUIE_ID_KEEP_ALIVE = 0x89,
+       WUIE_ID_ISOCH_DISCARD,
+       WUIE_ID_RESET_DEVICE,
+};
+
+/**
+ * Maximum number of array elements in a WUSB IE.
+ *
+ * WUSB1.0[7.5 before table 7-38] says that in WUSB IEs that
+ * are "arrays" have to limited to 4 elements. So we define it
+ * like that to ease up and submit only the neeed size.
+ */
+#define WUIE_ELT_MAX 4
+
+/**
+ * Wrapper for the data that defines a CHID, a CDID or a CK
+ *
+ * WUSB defines that CHIDs, CDIDs and CKs are a 16 byte string of
+ * data. In order to avoid confusion and enforce types, we wrap it.
+ *
+ * Make it packed, as we use it in some hw definitions.
+ */
+struct wusb_ckhdid {
+       u8 data[16];
+} __attribute__((packed));
+
+static const struct wusb_ckhdid wusb_ckhdid_zero = { .data = { 0 } };
+
+#define WUSB_CKHDID_STRSIZE (3 * sizeof(struct wusb_ckhdid) + 1)
+
+/**
+ * WUSB IE: Host Information (WUSB1.0[7.5.2])
+ *
+ * Used to provide information about the host to the Wireless USB
+ * devices in range (CHID can be used as an ASCII string).
+ */
+struct wuie_host_info {
+       struct wuie_hdr hdr;
+       __le16 attributes;
+       struct wusb_ckhdid CHID;
+} __attribute__((packed));
+
+/**
+ * WUSB IE: Connect Ack (WUSB1.0[7.5.1])
+ *
+ * Used to acknowledge device connect requests. See note for
+ * WUIE_ELT_MAX.
+ */
+struct wuie_connect_ack {
+       struct wuie_hdr hdr;
+       struct {
+               struct wusb_ckhdid CDID;
+               u8 bDeviceAddress;      /* 0 means unused */
+               u8 bReserved;
+       } blk[WUIE_ELT_MAX];
+} __attribute__((packed));
+
+/**
+ * WUSB IE Host Information Element, Connect Availability
+ *
+ * WUSB1.0[7.5.2], bmAttributes description
+ */
+enum {
+       WUIE_HI_CAP_RECONNECT = 0,
+       WUIE_HI_CAP_LIMITED,
+       WUIE_HI_CAP_RESERVED,
+       WUIE_HI_CAP_ALL,
+};
+
+/**
+ * WUSB IE: Channel Stop (WUSB1.0[7.5.8])
+ *
+ * Tells devices the host is going to stop sending MMCs and will disappear.
+ */
+struct wuie_channel_stop {
+       struct wuie_hdr hdr;
+       u8 attributes;
+       u8 timestamp[3];
+} __attribute__((packed));
+
+/**
+ * WUSB IE: Keepalive (WUSB1.0[7.5.9])
+ *
+ * Ask device(s) to send keepalives.
+ */
+struct wuie_keep_alive {
+       struct wuie_hdr hdr;
+       u8 bDeviceAddress[WUIE_ELT_MAX];
+} __attribute__((packed));
+
+/**
+ * WUSB IE: Reset device (WUSB1.0[7.5.11])
+ *
+ * Tell device to reset; in all truth, we can fit 4 CDIDs, but we only
+ * use it for one at the time...
+ *
+ * In any case, this request is a wee bit silly: why don't they target
+ * by address??
+ */
+struct wuie_reset {
+       struct wuie_hdr hdr;
+       struct wusb_ckhdid CDID;
+} __attribute__((packed));
+
+/**
+ * WUSB IE: Disconnect device (WUSB1.0[7.5.11])
+ *
+ * Tell device to disconnect; we can fit 4 addresses, but we only use
+ * it for one at the time...
+ */
+struct wuie_disconnect {
+       struct wuie_hdr hdr;
+       u8 bDeviceAddress;
+       u8 padding;
+} __attribute__((packed));
+
+/**
+ * WUSB IE: Host disconnect ([WUSB] section 7.5.5)
+ *
+ * Tells all connected devices to disconnect.
+ */
+struct wuie_host_disconnect {
+       struct wuie_hdr hdr;
+} __attribute__((packed));
+
+/**
+ * WUSB Device Notification header (WUSB1.0[7.6])
+ */
+struct wusb_dn_hdr {
+       u8 bType;
+       u8 notifdata[];
+} __attribute__((packed));
+
+/** Device Notification codes (WUSB1.0[Table 7-54]) */
+enum WUSB_DN {
+       WUSB_DN_CONNECT = 0x01,
+       WUSB_DN_DISCONNECT = 0x02,
+       WUSB_DN_EPRDY = 0x03,
+       WUSB_DN_MASAVAILCHANGED = 0x04,
+       WUSB_DN_RWAKE = 0x05,
+       WUSB_DN_SLEEP = 0x06,
+       WUSB_DN_ALIVE = 0x07,
+};
+
+/** WUSB Device Notification Connect */
+struct wusb_dn_connect {
+       struct wusb_dn_hdr hdr;
+       __le16 attributes;
+       struct wusb_ckhdid CDID;
+} __attribute__((packed));
+
+static inline int wusb_dn_connect_prev_dev_addr(const struct wusb_dn_connect *dn)
+{
+       return le16_to_cpu(dn->attributes) & 0xff;
+}
+
+static inline int wusb_dn_connect_new_connection(const struct wusb_dn_connect *dn)
+{
+       return (le16_to_cpu(dn->attributes) >> 8) & 0x1;
+}
+
+static inline int wusb_dn_connect_beacon_behavior(const struct wusb_dn_connect *dn)
+{
+       return (le16_to_cpu(dn->attributes) >> 9) & 0x03;
+}
+
+/** Device is alive (aka: pong) (WUSB1.0[7.6.7]) */
+struct wusb_dn_alive {
+       struct wusb_dn_hdr hdr;
+} __attribute__((packed));
+
+/** Device is disconnecting (WUSB1.0[7.6.2]) */
+struct wusb_dn_disconnect {
+       struct wusb_dn_hdr hdr;
+} __attribute__((packed));
+
+/* General constants */
+enum {
+       WUSB_TRUST_TIMEOUT_MS = 4000,   /* [WUSB] section 4.15.1 */
+};
+
+/*
+ * WUSB Crypto stuff (WUSB1.0[6])
+ */
+
+extern const char *wusb_et_name(u8);
+
+/**
+ * WUSB key index WUSB1.0[7.3.2.4], for usage when setting keys for
+ * the host or the device.
+ */
+static inline u8 wusb_key_index(int index, int type, int originator)
+{
+       return (originator << 6) | (type << 4) | index;
+}
+
+#define WUSB_KEY_INDEX_TYPE_PTK                        0 /* for HWA only */
+#define WUSB_KEY_INDEX_TYPE_ASSOC              1
+#define WUSB_KEY_INDEX_TYPE_GTK                        2
+#define WUSB_KEY_INDEX_ORIGINATOR_HOST         0
+#define WUSB_KEY_INDEX_ORIGINATOR_DEVICE       1
+/* bits 0-3 used for the key index. */
+#define WUSB_KEY_INDEX_MAX                     15
+
+/* A CCM Nonce, defined in WUSB1.0[6.4.1] */
+struct aes_ccm_nonce {
+       u8 sfn[6];              /* Little Endian */
+       u8 tkid[3];             /* LE */
+       struct uwb_dev_addr dest_addr;
+       struct uwb_dev_addr src_addr;
+} __attribute__((packed));
+
+/* A CCM operation label, defined on WUSB1.0[6.5.x] */
+struct aes_ccm_label {
+       u8 data[14];
+} __attribute__((packed));
+
+/*
+ * Input to the key derivation sequence defined in
+ * WUSB1.0[6.5.1]. Rest of the data is in the CCM Nonce passed to the
+ * PRF function.
+ */
+struct wusb_keydvt_in {
+       u8 hnonce[16];
+       u8 dnonce[16];
+} __attribute__((packed));
+
+/*
+ * Output from the key derivation sequence defined in
+ * WUSB1.0[6.5.1].
+ */
+struct wusb_keydvt_out {
+       u8 kck[16];
+       u8 ptk[16];
+} __attribute__((packed));
+
+/* Pseudo Random Function WUSB1.0[6.5] */
+extern int wusb_crypto_init(void);
+extern void wusb_crypto_exit(void);
+extern ssize_t wusb_prf(void *out, size_t out_size,
+                       const u8 key[16], const struct aes_ccm_nonce *_n,
+                       const struct aes_ccm_label *a,
+                       const void *b, size_t blen, size_t len);
+
+static inline int wusb_prf_64(void *out, size_t out_size, const u8 key[16],
+                             const struct aes_ccm_nonce *n,
+                             const struct aes_ccm_label *a,
+                             const void *b, size_t blen)
+{
+       return wusb_prf(out, out_size, key, n, a, b, blen, 64);
+}
+
+static inline int wusb_prf_128(void *out, size_t out_size, const u8 key[16],
+                              const struct aes_ccm_nonce *n,
+                              const struct aes_ccm_label *a,
+                              const void *b, size_t blen)
+{
+       return wusb_prf(out, out_size, key, n, a, b, blen, 128);
+}
+
+static inline int wusb_prf_256(void *out, size_t out_size, const u8 key[16],
+                              const struct aes_ccm_nonce *n,
+                              const struct aes_ccm_label *a,
+                              const void *b, size_t blen)
+{
+       return wusb_prf(out, out_size, key, n, a, b, blen, 256);
+}
+
+/* Key derivation WUSB1.0[6.5.1] */
+static inline int wusb_key_derive(struct wusb_keydvt_out *keydvt_out,
+                                 const u8 key[16],
+                                 const struct aes_ccm_nonce *n,
+                                 const struct wusb_keydvt_in *keydvt_in)
+{
+       const struct aes_ccm_label a = { .data = "Pair-wise keys" };
+       return wusb_prf_256(keydvt_out, sizeof(*keydvt_out), key, n, &a,
+                           keydvt_in, sizeof(*keydvt_in));
+}
+
+/*
+ * Out-of-band MIC Generation WUSB1.0[6.5.2]
+ *
+ * Compute the MIC over @key, @n and @hs and place it in @mic_out.
+ *
+ * @mic_out:  Where to place the 8 byte MIC tag
+ * @key:      KCK from the derivation process
+ * @n:        CCM nonce, n->sfn == 0, TKID as established in the
+ *            process.
+ * @hs:       Handshake struct for phase 2 of the 4-way.
+ *            hs->bStatus and hs->bReserved are zero.
+ *            hs->bMessageNumber is 2 (WUSB1.0[7.3.2.5.2]
+ *            hs->dest_addr is the device's USB address padded with 0
+ *            hs->src_addr is the hosts's UWB device address
+ *            hs->mic is ignored (as we compute that value).
+ */
+static inline int wusb_oob_mic(u8 mic_out[8], const u8 key[16],
+                              const struct aes_ccm_nonce *n,
+                              const struct usb_handshake *hs)
+{
+       const struct aes_ccm_label a = { .data = "out-of-bandMIC" };
+       return wusb_prf_64(mic_out, 8, key, n, &a,
+                          hs, sizeof(*hs) - sizeof(hs->MIC));
+}
+
+#endif /* #ifndef __WUSB_H__ */
diff --git a/drivers/staging/wusbcore/mmc.c b/drivers/staging/wusbcore/mmc.c
new file mode 100644 (file)
index 0000000..881e1f2
--- /dev/null
@@ -0,0 +1,303 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
+ * MMC (Microscheduled Management Command) handling
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * WUIEs and MMC IEs...well, they are almost the same at the end. MMC
+ * IEs are Wireless USB IEs that go into the MMC period...[what is
+ * that? look in Design-overview.txt].
+ *
+ *
+ * This is a simple subsystem to keep track of which IEs are being
+ * sent by the host in the MMC period.
+ *
+ * For each WUIE we ask to send, we keep it in an array, so we can
+ * request its removal later, or replace the content. They are tracked
+ * by pointer, so be sure to use the same pointer if you want to
+ * remove it or update the contents.
+ *
+ * FIXME:
+ *  - add timers that autoremove intervalled IEs?
+ */
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "include/wusb.h"
+#include "wusbhc.h"
+
+/* Initialize the MMCIEs handling mechanism */
+int wusbhc_mmcie_create(struct wusbhc *wusbhc)
+{
+       u8 mmcies = wusbhc->mmcies_max;
+       wusbhc->mmcie = kcalloc(mmcies, sizeof(wusbhc->mmcie[0]), GFP_KERNEL);
+       if (wusbhc->mmcie == NULL)
+               return -ENOMEM;
+       mutex_init(&wusbhc->mmcie_mutex);
+       return 0;
+}
+
+/* Release resources used by the MMCIEs handling mechanism */
+void wusbhc_mmcie_destroy(struct wusbhc *wusbhc)
+{
+       kfree(wusbhc->mmcie);
+}
+
+/*
+ * Add or replace an MMC Wireless USB IE.
+ *
+ * @interval:    See WUSB1.0[8.5.3.1]
+ * @repeat_cnt:  See WUSB1.0[8.5.3.1]
+ * @handle:      See WUSB1.0[8.5.3.1]
+ * @wuie:        Pointer to the header of the WUSB IE data to add.
+ *               MUST BE allocated in a kmalloc buffer (no stack or
+ *               vmalloc).
+ *               THE CALLER ALWAYS OWNS THE POINTER (we don't free it
+ *               on remove, we just forget about it).
+ * @returns:     0 if ok, < 0 errno code on error.
+ *
+ * Goes over the *whole* @wusbhc->mmcie array looking for (a) the
+ * first free spot and (b) if @wuie is already in the array (aka:
+ * transmitted in the MMCs) the spot were it is.
+ *
+ * If present, we "overwrite it" (update).
+ *
+ *
+ * NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38.
+ *       The host uses the handle as the 'sort' index. We
+ *       allocate the last one always for the WUIE_ID_HOST_INFO, and
+ *       the rest, first come first serve in inverse order.
+ *
+ *       Host software must make sure that it adds the other IEs in
+ *       the right order... the host hardware is responsible for
+ *       placing the WCTA IEs in the right place with the other IEs
+ *       set by host software.
+ *
+ * NOTE: we can access wusbhc->wa_descr without locking because it is
+ *       read only.
+ */
+int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+                    struct wuie_hdr *wuie)
+{
+       int result = -ENOBUFS;
+       unsigned handle, itr;
+
+       /* Search a handle, taking into account the ordering */
+       mutex_lock(&wusbhc->mmcie_mutex);
+       switch (wuie->bIEIdentifier) {
+       case WUIE_ID_HOST_INFO:
+               /* Always last */
+               handle = wusbhc->mmcies_max - 1;
+               break;
+       case WUIE_ID_ISOCH_DISCARD:
+               dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x "
+                       "unimplemented\n", wuie->bIEIdentifier);
+               result = -ENOSYS;
+               goto error_unlock;
+       default:
+               /* search for it or find the last empty slot */
+               handle = ~0;
+               for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) {
+                       if (wusbhc->mmcie[itr] == wuie) {
+                               handle = itr;
+                               break;
+                       }
+                       if (wusbhc->mmcie[itr] == NULL)
+                               handle = itr;
+               }
+               if (handle == ~0)
+                       goto error_unlock;
+       }
+       result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle,
+                                    wuie);
+       if (result >= 0)
+               wusbhc->mmcie[handle] = wuie;
+error_unlock:
+       mutex_unlock(&wusbhc->mmcie_mutex);
+       return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_mmcie_set);
+
+/*
+ * Remove an MMC IE previously added with wusbhc_mmcie_set()
+ *
+ * @wuie       Pointer used to add the WUIE
+ */
+void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie)
+{
+       int result;
+       unsigned handle, itr;
+
+       mutex_lock(&wusbhc->mmcie_mutex);
+       for (itr = 0; itr < wusbhc->mmcies_max; itr++) {
+               if (wusbhc->mmcie[itr] == wuie) {
+                       handle = itr;
+                       goto found;
+               }
+       }
+       mutex_unlock(&wusbhc->mmcie_mutex);
+       return;
+
+found:
+       result = (wusbhc->mmcie_rm)(wusbhc, handle);
+       if (result == 0)
+               wusbhc->mmcie[itr] = NULL;
+       mutex_unlock(&wusbhc->mmcie_mutex);
+}
+EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm);
+
+static int wusbhc_mmc_start(struct wusbhc *wusbhc)
+{
+       int ret;
+
+       mutex_lock(&wusbhc->mutex);
+       ret = wusbhc->start(wusbhc);
+       if (ret >= 0)
+               wusbhc->active = 1;
+       mutex_unlock(&wusbhc->mutex);
+
+       return ret;
+}
+
+static void wusbhc_mmc_stop(struct wusbhc *wusbhc)
+{
+       mutex_lock(&wusbhc->mutex);
+       wusbhc->active = 0;
+       wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS);
+       mutex_unlock(&wusbhc->mutex);
+}
+
+/*
+ * wusbhc_start - start transmitting MMCs and accepting connections
+ * @wusbhc: the HC to start
+ *
+ * Establishes a cluster reservation, enables device connections, and
+ * starts MMCs with appropriate DNTS parameters.
+ */
+int wusbhc_start(struct wusbhc *wusbhc)
+{
+       int result;
+       struct device *dev = wusbhc->dev;
+
+       WARN_ON(wusbhc->wuie_host_info != NULL);
+       BUG_ON(wusbhc->uwb_rc == NULL);
+
+       result = wusbhc_rsv_establish(wusbhc);
+       if (result < 0) {
+               dev_err(dev, "cannot establish cluster reservation: %d\n",
+                       result);
+               goto error_rsv_establish;
+       }
+
+       result = wusbhc_devconnect_start(wusbhc);
+       if (result < 0) {
+               dev_err(dev, "error enabling device connections: %d\n",
+                       result);
+               goto error_devconnect_start;
+       }
+
+       result = wusbhc_sec_start(wusbhc);
+       if (result < 0) {
+               dev_err(dev, "error starting security in the HC: %d\n",
+                       result);
+               goto error_sec_start;
+       }
+
+       result = wusbhc->set_num_dnts(wusbhc, wusbhc->dnts_interval,
+               wusbhc->dnts_num_slots);
+       if (result < 0) {
+               dev_err(dev, "Cannot set DNTS parameters: %d\n", result);
+               goto error_set_num_dnts;
+       }
+       result = wusbhc_mmc_start(wusbhc);
+       if (result < 0) {
+               dev_err(dev, "error starting wusbch: %d\n", result);
+               goto error_wusbhc_start;
+       }
+
+       return 0;
+
+error_wusbhc_start:
+       wusbhc_sec_stop(wusbhc);
+error_set_num_dnts:
+error_sec_start:
+       wusbhc_devconnect_stop(wusbhc);
+error_devconnect_start:
+       wusbhc_rsv_terminate(wusbhc);
+error_rsv_establish:
+       return result;
+}
+
+/*
+ * wusbhc_stop - stop transmitting MMCs
+ * @wusbhc: the HC to stop
+ *
+ * Stops the WUSB channel and removes the cluster reservation.
+ */
+void wusbhc_stop(struct wusbhc *wusbhc)
+{
+       wusbhc_mmc_stop(wusbhc);
+       wusbhc_sec_stop(wusbhc);
+       wusbhc_devconnect_stop(wusbhc);
+       wusbhc_rsv_terminate(wusbhc);
+}
+
+/*
+ * Set/reset/update a new CHID
+ *
+ * Depending on the previous state of the MMCs, start, stop or change
+ * the sent MMC. This effectively switches the host controller on and
+ * off (radio wise).
+ */
+int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
+{
+       int result = 0;
+
+       if (memcmp(chid, &wusb_ckhdid_zero, sizeof(*chid)) == 0)
+               chid = NULL;
+
+       mutex_lock(&wusbhc->mutex);
+       if (chid) {
+               if (wusbhc->active) {
+                       mutex_unlock(&wusbhc->mutex);
+                       return -EBUSY;
+               }
+               wusbhc->chid = *chid;
+       }
+
+       /* register with UWB if we haven't already since we are about to start
+           the radio. */
+       if ((chid) && (wusbhc->uwb_rc == NULL)) {
+               wusbhc->uwb_rc = uwb_rc_get_by_grandpa(wusbhc->dev->parent);
+               if (wusbhc->uwb_rc == NULL) {
+                       result = -ENODEV;
+                       dev_err(wusbhc->dev,
+                               "Cannot get associated UWB Host Controller\n");
+                       goto error_rc_get;
+               }
+
+               result = wusbhc_pal_register(wusbhc);
+               if (result < 0) {
+                       dev_err(wusbhc->dev, "Cannot register as a UWB PAL\n");
+                       goto error_pal_register;
+               }
+       }
+       mutex_unlock(&wusbhc->mutex);
+
+       if (chid)
+               result = uwb_radio_start(&wusbhc->pal);
+       else if (wusbhc->uwb_rc)
+               uwb_radio_stop(&wusbhc->pal);
+
+       return result;
+
+error_pal_register:
+       uwb_rc_put(wusbhc->uwb_rc);
+       wusbhc->uwb_rc = NULL;
+error_rc_get:
+       mutex_unlock(&wusbhc->mutex);
+
+       return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_chid_set);
diff --git a/drivers/staging/wusbcore/pal.c b/drivers/staging/wusbcore/pal.c
new file mode 100644 (file)
index 0000000..30f5691
--- /dev/null
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Host Controller
+ * UWB Protocol Adaptation Layer (PAL) glue.
+ *
+ * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
+ */
+#include "wusbhc.h"
+
+static void wusbhc_channel_changed(struct uwb_pal *pal, int channel)
+{
+       struct wusbhc *wusbhc = container_of(pal, struct wusbhc, pal);
+
+       dev_dbg(wusbhc->dev, "%s: channel = %d\n", __func__, channel);
+       if (channel < 0)
+               wusbhc_stop(wusbhc);
+       else
+               wusbhc_start(wusbhc);
+}
+
+/**
+ * wusbhc_pal_register - register the WUSB HC as a UWB PAL
+ * @wusbhc: the WUSB HC
+ */
+int wusbhc_pal_register(struct wusbhc *wusbhc)
+{
+       uwb_pal_init(&wusbhc->pal);
+
+       wusbhc->pal.name   = "wusbhc";
+       wusbhc->pal.device = wusbhc->usb_hcd.self.controller;
+       wusbhc->pal.rc     = wusbhc->uwb_rc;
+       wusbhc->pal.channel_changed = wusbhc_channel_changed;
+
+       return uwb_pal_register(&wusbhc->pal);
+}
+
+/**
+ * wusbhc_pal_unregister - unregister the WUSB HC as a UWB PAL
+ * @wusbhc: the WUSB HC
+ */
+void wusbhc_pal_unregister(struct wusbhc *wusbhc)
+{
+       if (wusbhc->uwb_rc)
+               uwb_pal_unregister(&wusbhc->pal);
+}
diff --git a/drivers/staging/wusbcore/reservation.c b/drivers/staging/wusbcore/reservation.c
new file mode 100644 (file)
index 0000000..b921faa
--- /dev/null
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB cluster reservation management
+ *
+ * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
+ */
+#include <linux/kernel.h>
+
+#include "../uwb/uwb.h"
+#include "wusbhc.h"
+
+/*
+ * WUSB cluster reservations are multicast reservations with the
+ * broadcast cluster ID (BCID) as the target DevAddr.
+ *
+ * FIXME: consider adjusting the reservation depending on what devices
+ * are attached.
+ */
+
+static int wusbhc_bwa_set(struct wusbhc *wusbhc, u8 stream,
+       const struct uwb_mas_bm *mas)
+{
+       if (mas == NULL)
+               mas = &uwb_mas_bm_zero;
+       return wusbhc->bwa_set(wusbhc, stream, mas);
+}
+
+/**
+ * wusbhc_rsv_complete_cb - WUSB HC reservation complete callback
+ * @rsv:    the reservation
+ *
+ * Either set or clear the HC's view of the reservation.
+ *
+ * FIXME: when a reservation is denied the HC should be stopped.
+ */
+static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv)
+{
+       struct wusbhc *wusbhc = rsv->pal_priv;
+       struct device *dev = wusbhc->dev;
+       struct uwb_mas_bm mas;
+
+       dev_dbg(dev, "%s: state = %d\n", __func__, rsv->state);
+       switch (rsv->state) {
+       case UWB_RSV_STATE_O_ESTABLISHED:
+               uwb_rsv_get_usable_mas(rsv, &mas);
+               dev_dbg(dev, "established reservation: %*pb\n",
+                       UWB_NUM_MAS, mas.bm);
+               wusbhc_bwa_set(wusbhc, rsv->stream, &mas);
+               break;
+       case UWB_RSV_STATE_NONE:
+               dev_dbg(dev, "removed reservation\n");
+               wusbhc_bwa_set(wusbhc, 0, NULL);
+               break;
+       default:
+               dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state);
+               break;
+       }
+}
+
+
+/**
+ * wusbhc_rsv_establish - establish a reservation for the cluster
+ * @wusbhc: the WUSB HC requesting a bandwidth reservation
+ */
+int wusbhc_rsv_establish(struct wusbhc *wusbhc)
+{
+       struct uwb_rc *rc = wusbhc->uwb_rc;
+       struct uwb_rsv *rsv;
+       struct uwb_dev_addr bcid;
+       int ret;
+
+       if (rc == NULL)
+               return -ENODEV;
+
+       rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc);
+       if (rsv == NULL)
+               return -ENOMEM;
+
+       bcid.data[0] = wusbhc->cluster_id;
+       bcid.data[1] = 0;
+
+       rsv->target.type = UWB_RSV_TARGET_DEVADDR;
+       rsv->target.devaddr = bcid;
+       rsv->type = UWB_DRP_TYPE_PRIVATE;
+       rsv->max_mas = 256; /* try to get as much as possible */
+       rsv->min_mas = 15;  /* one MAS per zone */
+       rsv->max_interval = 1; /* max latency is one zone */
+       rsv->is_multicast = true;
+
+       ret = uwb_rsv_establish(rsv);
+       if (ret == 0)
+               wusbhc->rsv = rsv;
+       else
+               uwb_rsv_destroy(rsv);
+       return ret;
+}
+
+
+/**
+ * wusbhc_rsv_terminate - terminate the cluster reservation
+ * @wusbhc: the WUSB host whose reservation is to be terminated
+ */
+void wusbhc_rsv_terminate(struct wusbhc *wusbhc)
+{
+       if (wusbhc->rsv) {
+               uwb_rsv_terminate(wusbhc->rsv);
+               uwb_rsv_destroy(wusbhc->rsv);
+               wusbhc->rsv = NULL;
+       }
+}
diff --git a/drivers/staging/wusbcore/rh.c b/drivers/staging/wusbcore/rh.c
new file mode 100644 (file)
index 0000000..20c08cd
--- /dev/null
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Host Controller
+ * Root Hub operations
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * We fake a root hub that has fake ports (as many as simultaneous
+ * devices the Wireless USB Host Controller can deal with). For each
+ * port we keep an state in @wusbhc->port[index] identical to the one
+ * specified in the USB2.0[ch11] spec and some extra device
+ * information that complements the one in 'struct usb_device' (as
+ * this lacs a hcpriv pointer).
+ *
+ * Note this is common to WHCI and HWA host controllers.
+ *
+ * Through here we enable most of the state changes that the USB stack
+ * will use to connect or disconnect devices. We need to do some
+ * forced adaptation of Wireless USB device states vs. wired:
+ *
+ *        USB:                 WUSB:
+ *
+ * Port   Powered-off          port slot n/a
+ *        Powered-on           port slot available
+ *        Disconnected         port slot available
+ *        Connected            port slot assigned device
+ *                            device sent DN_Connect
+ *                             device was authenticated
+ *        Enabled              device is authenticated, transitioned
+ *                             from unauth -> auth -> default address
+ *                             -> enabled
+ *        Reset                disconnect
+ *        Disable              disconnect
+ *
+ * This maps the standard USB port states with the WUSB device states
+ * so we can fake ports without having to modify the USB stack.
+ *
+ * FIXME: this process will change in the future
+ *
+ *
+ * ENTRY POINTS
+ *
+ * Our entry points into here are, as in hcd.c, the USB stack root hub
+ * ops defined in the usb_hcd struct:
+ *
+ * wusbhc_rh_status_data()     Provide hub and port status data bitmap
+ *
+ * wusbhc_rh_control()          Execution of all the major requests
+ *                              you can do to a hub (Set|Clear
+ *                              features, get descriptors, status, etc).
+ *
+ * wusbhc_rh_[suspend|resume]() That
+ *
+ * wusbhc_rh_start_port_reset() ??? unimplemented
+ */
+#include <linux/slab.h>
+#include <linux/export.h>
+#include "wusbhc.h"
+
+/*
+ * Reset a fake port
+ *
+ * Using a Reset Device IE is too heavyweight as it causes the device
+ * to enter the UnConnected state and leave the cluster, this can mean
+ * that when the device reconnects it is connected to a different fake
+ * port.
+ *
+ * Instead, reset authenticated devices with a SetAddress(0), followed
+ * by a SetAddresss(AuthAddr).
+ *
+ * For unauthenticated devices just pretend to reset but do nothing.
+ * If the device initialization continues to fail it will eventually
+ * time out after TrustTimeout and enter the UnConnected state.
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * Supposedly we are the only thread accesing @wusbhc->port; in any
+ * case, maybe we should move the mutex locking from
+ * wusbhc_devconnect_auth() to here.
+ *
+ * @port_idx refers to the wusbhc's port index, not the USB port number
+ */
+static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx)
+{
+       int result = 0;
+       struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx);
+       struct wusb_dev *wusb_dev = port->wusb_dev;
+
+       if (wusb_dev == NULL)
+               return -ENOTCONN;
+
+       port->status |= USB_PORT_STAT_RESET;
+       port->change |= USB_PORT_STAT_C_RESET;
+
+       if (wusb_dev->addr & WUSB_DEV_ADDR_UNAUTH)
+               result = 0;
+       else
+               result = wusb_dev_update_address(wusbhc, wusb_dev);
+
+       port->status &= ~USB_PORT_STAT_RESET;
+       port->status |= USB_PORT_STAT_ENABLE;
+       port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE; 
+
+       return result;
+}
+
+/*
+ * Return the hub change status bitmap
+ *
+ * The bits in the change status bitmap are cleared when a
+ * ClearPortFeature request is issued (USB2.0[11.12.3,11.12.4].
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * WARNING!! This gets called from atomic context; we cannot get the
+ *           mutex--the only race condition we can find is some bit
+ *           changing just after we copy it, which shouldn't be too
+ *           big of a problem [and we can't make it an spinlock
+ *           because other parts need to take it and sleep] .
+ *
+ *           @usb_hcd is refcounted, so it won't disappear under us
+ *           and before killing a host, the polling of the root hub
+ *           would be stopped anyway.
+ */
+int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       size_t cnt, size, bits_set = 0;
+
+       /* WE DON'T LOCK, see comment */
+       /* round up to bytes.  Hub bit is bit 0 so add 1. */
+       size = DIV_ROUND_UP(wusbhc->ports_max + 1, 8);
+
+       /* clear the output buffer. */
+       memset(_buf, 0, size);
+       /* set the bit for each changed port. */
+       for (cnt = 0; cnt < wusbhc->ports_max; cnt++) {
+
+               if (wusb_port_by_idx(wusbhc, cnt)->change) {
+                       const int bitpos = cnt+1;
+
+                       _buf[bitpos/8] |= (1 << (bitpos % 8));
+                       bits_set++;
+               }
+       }
+
+       return bits_set ? size : 0;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_status_data);
+
+/*
+ * Return the hub's descriptor
+ *
+ * NOTE: almost cut and paste from ehci-hub.c
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked
+ */
+static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue,
+                                  u16 wIndex,
+                                  struct usb_hub_descriptor *descr,
+                                  u16 wLength)
+{
+       u16 temp = 1 + (wusbhc->ports_max / 8);
+       u8 length = 7 + 2 * temp;
+
+       if (wLength < length)
+               return -ENOSPC;
+       descr->bDescLength = 7 + 2 * temp;
+       descr->bDescriptorType = USB_DT_HUB; /* HUB type */
+       descr->bNbrPorts = wusbhc->ports_max;
+       descr->wHubCharacteristics = cpu_to_le16(
+               HUB_CHAR_COMMON_LPSM    /* All ports power at once */
+               | 0x00                  /* not part of compound device */
+               | HUB_CHAR_NO_OCPM      /* No overcurrent protection */
+               | 0x00                  /* 8 FS think time FIXME ?? */
+               | 0x00);                /* No port indicators */
+       descr->bPwrOn2PwrGood = 0;
+       descr->bHubContrCurrent = 0;
+       /* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+       memset(&descr->u.hs.DeviceRemovable[0], 0, temp);
+       memset(&descr->u.hs.DeviceRemovable[temp], 0xff, temp);
+       return 0;
+}
+
+/*
+ * Clear a hub feature
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * Nothing to do, so no locking needed ;)
+ */
+static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature)
+{
+       int result;
+
+       switch (feature) {
+       case C_HUB_LOCAL_POWER:
+               /* FIXME: maybe plug bit 0 to the power input status,
+                * if any?
+                * see wusbhc_rh_get_hub_status() */
+       case C_HUB_OVER_CURRENT:
+               result = 0;
+               break;
+       default:
+               result = -EPIPE;
+       }
+       return result;
+}
+
+/*
+ * Return hub status (it is always zero...)
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ *
+ * Nothing to do, so no locking needed ;)
+ */
+static int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf,
+                                   u16 wLength)
+{
+       /* FIXME: maybe plug bit 0 to the power input status (if any)? */
+       *buf = 0;
+       return 0;
+}
+
+/*
+ * Set a port feature
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature,
+                                  u8 selector, u8 port_idx)
+{
+       struct device *dev = wusbhc->dev;
+
+       if (port_idx > wusbhc->ports_max)
+               return -EINVAL;
+
+       switch (feature) {
+               /* According to USB2.0[11.24.2.13]p2, these features
+                * are not required to be implemented. */
+       case USB_PORT_FEAT_C_OVER_CURRENT:
+       case USB_PORT_FEAT_C_ENABLE:
+       case USB_PORT_FEAT_C_SUSPEND:
+       case USB_PORT_FEAT_C_CONNECTION:
+       case USB_PORT_FEAT_C_RESET:
+               return 0;
+       case USB_PORT_FEAT_POWER:
+               /* No such thing, but we fake it works */
+               mutex_lock(&wusbhc->mutex);
+               wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER;
+               mutex_unlock(&wusbhc->mutex);
+               return 0;
+       case USB_PORT_FEAT_RESET:
+               return wusbhc_rh_port_reset(wusbhc, port_idx);
+       case USB_PORT_FEAT_ENABLE:
+       case USB_PORT_FEAT_SUSPEND:
+               dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n",
+                       port_idx, feature, selector);
+               return -ENOSYS;
+       default:
+               dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n",
+                       port_idx, feature, selector);
+               return -EPIPE;
+       }
+
+       return 0;
+}
+
+/*
+ * Clear a port feature...
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature,
+                                    u8 selector, u8 port_idx)
+{
+       int result = 0;
+       struct device *dev = wusbhc->dev;
+
+       if (port_idx > wusbhc->ports_max)
+               return -EINVAL;
+
+       mutex_lock(&wusbhc->mutex);
+       switch (feature) {
+       case USB_PORT_FEAT_POWER:       /* fake port always on */
+               /* According to USB2.0[11.24.2.7.1.4], no need to implement? */
+       case USB_PORT_FEAT_C_OVER_CURRENT:
+               break;
+       case USB_PORT_FEAT_C_RESET:
+               wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_RESET;
+               break;
+       case USB_PORT_FEAT_C_CONNECTION:
+               wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_CONNECTION;
+               break;
+       case USB_PORT_FEAT_ENABLE:
+               __wusbhc_dev_disable(wusbhc, port_idx);
+               break;
+       case USB_PORT_FEAT_C_ENABLE:
+               wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_ENABLE;
+               break;
+       case USB_PORT_FEAT_SUSPEND:
+       case USB_PORT_FEAT_C_SUSPEND:
+               dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n",
+                       port_idx, feature, selector);
+               result = -ENOSYS;
+               break;
+       default:
+               dev_err(dev, "(port_idx %d) Clear feat %d/%d UNKNOWN\n",
+                       port_idx, feature, selector);
+               result = -EPIPE;
+               break;
+       }
+       mutex_unlock(&wusbhc->mutex);
+
+       return result;
+}
+
+/*
+ * Return the port's status
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx,
+                                    u32 *_buf, u16 wLength)
+{
+       __le16 *buf = (__le16 *)_buf;
+
+       if (port_idx > wusbhc->ports_max)
+               return -EINVAL;
+
+       mutex_lock(&wusbhc->mutex);
+       buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status);
+       buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change);
+       mutex_unlock(&wusbhc->mutex);
+
+       return 0;
+}
+
+/*
+ * Entry point for Root Hub operations
+ *
+ * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
+ */
+int wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue,
+                     u16 wIndex, char *buf, u16 wLength)
+{
+       int result = -ENOSYS;
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+
+       switch (reqntype) {
+       case GetHubDescriptor:
+               result = wusbhc_rh_get_hub_descr(
+                       wusbhc, wValue, wIndex,
+                       (struct usb_hub_descriptor *) buf, wLength);
+               break;
+       case ClearHubFeature:
+               result = wusbhc_rh_clear_hub_feat(wusbhc, wValue);
+               break;
+       case GetHubStatus:
+               result = wusbhc_rh_get_hub_status(wusbhc, (u32 *)buf, wLength);
+               break;
+
+       case SetPortFeature:
+               result = wusbhc_rh_set_port_feat(wusbhc, wValue, wIndex >> 8,
+                                                (wIndex & 0xff) - 1);
+               break;
+       case ClearPortFeature:
+               result = wusbhc_rh_clear_port_feat(wusbhc, wValue, wIndex >> 8,
+                                                  (wIndex & 0xff) - 1);
+               break;
+       case GetPortStatus:
+               result = wusbhc_rh_get_port_status(wusbhc, wIndex - 1,
+                                                  (u32 *)buf, wLength);
+               break;
+
+       case SetHubFeature:
+       default:
+               dev_err(wusbhc->dev, "%s (%p [%p], %x, %x, %x, %p, %x) "
+                       "UNIMPLEMENTED\n", __func__, usb_hcd, wusbhc, reqntype,
+                       wValue, wIndex, buf, wLength);
+               /* dump_stack(); */
+               result = -ENOSYS;
+       }
+       return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_control);
+
+int wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx)
+{
+       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+       dev_err(wusbhc->dev, "%s (%p [%p], port_idx %u) UNIMPLEMENTED\n",
+               __func__, usb_hcd, wusbhc, port_idx);
+       WARN_ON(1);
+       return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(wusbhc_rh_start_port_reset);
+
+static void wusb_port_init(struct wusb_port *port)
+{
+       port->status |= USB_PORT_STAT_HIGH_SPEED;
+}
+
+/*
+ * Alloc fake port specific fields and status.
+ */
+int wusbhc_rh_create(struct wusbhc *wusbhc)
+{
+       int result = -ENOMEM;
+       size_t port_size, itr;
+       port_size = wusbhc->ports_max * sizeof(wusbhc->port[0]);
+       wusbhc->port = kzalloc(port_size, GFP_KERNEL);
+       if (wusbhc->port == NULL)
+               goto error_port_alloc;
+       for (itr = 0; itr < wusbhc->ports_max; itr++)
+               wusb_port_init(&wusbhc->port[itr]);
+       result = 0;
+error_port_alloc:
+       return result;
+}
+
+void wusbhc_rh_destroy(struct wusbhc *wusbhc)
+{
+       kfree(wusbhc->port);
+}
diff --git a/drivers/staging/wusbcore/security.c b/drivers/staging/wusbcore/security.c
new file mode 100644 (file)
index 0000000..14ac8c9
--- /dev/null
@@ -0,0 +1,599 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Host Controller
+ * Security support: encryption enablement, etc
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ */
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/usb/ch9.h>
+#include <linux/random.h>
+#include <linux/export.h>
+#include "wusbhc.h"
+#include <asm/unaligned.h>
+
+static void wusbhc_gtk_rekey_work(struct work_struct *work);
+
+int wusbhc_sec_create(struct wusbhc *wusbhc)
+{
+       /*
+        * WQ is singlethread because we need to serialize rekey operations.
+        * Use a separate workqueue for security operations instead of the
+        * wusbd workqueue because security operations may need to communicate
+        * directly with downstream wireless devices using synchronous URBs.
+        * If a device is not responding, this could block other host
+        * controller operations.
+        */
+       wusbhc->wq_security = create_singlethread_workqueue("wusbd_security");
+       if (wusbhc->wq_security == NULL) {
+               pr_err("WUSB-core: Cannot create wusbd_security workqueue\n");
+               return -ENOMEM;
+       }
+
+       wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) +
+               sizeof(wusbhc->gtk.data);
+       wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY;
+       wusbhc->gtk.descr.bReserved = 0;
+       wusbhc->gtk_index = 0;
+
+       INIT_WORK(&wusbhc->gtk_rekey_work, wusbhc_gtk_rekey_work);
+
+       return 0;
+}
+
+
+/* Called when the HC is destroyed */
+void wusbhc_sec_destroy(struct wusbhc *wusbhc)
+{
+       destroy_workqueue(wusbhc->wq_security);
+}
+
+
+/**
+ * wusbhc_next_tkid - generate a new, currently unused, TKID
+ * @wusbhc:   the WUSB host controller
+ * @wusb_dev: the device whose PTK the TKID is for
+ *            (or NULL for a TKID for a GTK)
+ *
+ * The generated TKID consists of two parts: the device's authenticated
+ * address (or 0 or a GTK); and an incrementing number.  This ensures
+ * that TKIDs cannot be shared between devices and by the time the
+ * incrementing number wraps around the older TKIDs will no longer be
+ * in use (a maximum of two keys may be active at any one time).
+ */
+static u32 wusbhc_next_tkid(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+       u32 *tkid;
+       u32 addr;
+
+       if (wusb_dev == NULL) {
+               tkid = &wusbhc->gtk_tkid;
+               addr = 0;
+       } else {
+               tkid = &wusb_port_by_idx(wusbhc, wusb_dev->port_idx)->ptk_tkid;
+               addr = wusb_dev->addr & 0x7f;
+       }
+
+       *tkid = (addr << 8) | ((*tkid + 1) & 0xff);
+
+       return *tkid;
+}
+
+static void wusbhc_generate_gtk(struct wusbhc *wusbhc)
+{
+       const size_t key_size = sizeof(wusbhc->gtk.data);
+       u32 tkid;
+
+       tkid = wusbhc_next_tkid(wusbhc, NULL);
+
+       wusbhc->gtk.descr.tTKID[0] = (tkid >>  0) & 0xff;
+       wusbhc->gtk.descr.tTKID[1] = (tkid >>  8) & 0xff;
+       wusbhc->gtk.descr.tTKID[2] = (tkid >> 16) & 0xff;
+
+       get_random_bytes(wusbhc->gtk.descr.bKeyData, key_size);
+}
+
+/**
+ * wusbhc_sec_start - start the security management process
+ * @wusbhc: the WUSB host controller
+ *
+ * Generate and set an initial GTK on the host controller.
+ *
+ * Called when the HC is started.
+ */
+int wusbhc_sec_start(struct wusbhc *wusbhc)
+{
+       const size_t key_size = sizeof(wusbhc->gtk.data);
+       int result;
+
+       wusbhc_generate_gtk(wusbhc);
+
+       result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
+                               &wusbhc->gtk.descr.bKeyData, key_size);
+       if (result < 0)
+               dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n",
+                       result);
+
+       return result;
+}
+
+/**
+ * wusbhc_sec_stop - stop the security management process
+ * @wusbhc: the WUSB host controller
+ *
+ * Wait for any pending GTK rekeys to stop.
+ */
+void wusbhc_sec_stop(struct wusbhc *wusbhc)
+{
+       cancel_work_sync(&wusbhc->gtk_rekey_work);
+}
+
+
+/** @returns encryption type name */
+const char *wusb_et_name(u8 x)
+{
+       switch (x) {
+       case USB_ENC_TYPE_UNSECURE:     return "unsecure";
+       case USB_ENC_TYPE_WIRED:        return "wired";
+       case USB_ENC_TYPE_CCM_1:        return "CCM-1";
+       case USB_ENC_TYPE_RSA_1:        return "RSA-1";
+       default:                        return "unknown";
+       }
+}
+EXPORT_SYMBOL_GPL(wusb_et_name);
+
+/*
+ * Set the device encryption method
+ *
+ * We tell the device which encryption method to use; we do this when
+ * setting up the device's security.
+ */
+static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value)
+{
+       int result;
+       struct device *dev = &usb_dev->dev;
+       struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
+
+       if (value) {
+               value = wusb_dev->ccm1_etd.bEncryptionValue;
+       } else {
+               /* FIXME: should be wusb_dev->etd[UNSECURE].bEncryptionValue */
+               value = 0;
+       }
+       /* Set device's */
+       result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                       USB_REQ_SET_ENCRYPTION,
+                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                       value, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (result < 0)
+               dev_err(dev, "Can't set device's WUSB encryption to "
+                       "%s (value %d): %d\n",
+                       wusb_et_name(wusb_dev->ccm1_etd.bEncryptionType),
+                       wusb_dev->ccm1_etd.bEncryptionValue,  result);
+       return result;
+}
+
+/*
+ * Set the GTK to be used by a device.
+ *
+ * The device must be authenticated.
+ */
+static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+       struct usb_device *usb_dev = wusb_dev->usb_dev;
+       u8 key_index = wusb_key_index(wusbhc->gtk_index,
+               WUSB_KEY_INDEX_TYPE_GTK, WUSB_KEY_INDEX_ORIGINATOR_HOST);
+
+       return usb_control_msg(
+               usb_dev, usb_sndctrlpipe(usb_dev, 0),
+               USB_REQ_SET_DESCRIPTOR,
+               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+               USB_DT_KEY << 8 | key_index, 0,
+               &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength,
+               USB_CTRL_SET_TIMEOUT);
+}
+
+
+/* FIXME: prototype for adding security */
+int wusb_dev_sec_add(struct wusbhc *wusbhc,
+                    struct usb_device *usb_dev, struct wusb_dev *wusb_dev)
+{
+       int result, bytes, secd_size;
+       struct device *dev = &usb_dev->dev;
+       struct usb_security_descriptor *secd, *new_secd;
+       const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
+       const void *itr, *top;
+       char buf[64];
+
+       secd = kmalloc(sizeof(*secd), GFP_KERNEL);
+       if (secd == NULL) {
+               result = -ENOMEM;
+               goto out;
+       }
+
+       result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
+                                   0, secd, sizeof(*secd));
+       if (result < (int)sizeof(*secd)) {
+               dev_err(dev, "Can't read security descriptor or "
+                       "not enough data: %d\n", result);
+               goto out;
+       }
+       secd_size = le16_to_cpu(secd->wTotalLength);
+       new_secd = krealloc(secd, secd_size, GFP_KERNEL);
+       if (new_secd == NULL) {
+               dev_err(dev,
+                       "Can't allocate space for security descriptors\n");
+               result = -ENOMEM;
+               goto out;
+       }
+       secd = new_secd;
+       result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
+                                   0, secd, secd_size);
+       if (result < secd_size) {
+               dev_err(dev, "Can't read security descriptor or "
+                       "not enough data: %d\n", result);
+               goto out;
+       }
+       bytes = 0;
+       itr = &secd[1];
+       top = (void *)secd + result;
+       while (itr < top) {
+               etd = itr;
+               if (top - itr < sizeof(*etd)) {
+                       dev_err(dev, "BUG: bad device security descriptor; "
+                               "not enough data (%zu vs %zu bytes left)\n",
+                               top - itr, sizeof(*etd));
+                       break;
+               }
+               if (etd->bLength < sizeof(*etd)) {
+                       dev_err(dev, "BUG: bad device encryption descriptor; "
+                               "descriptor is too short "
+                               "(%u vs %zu needed)\n",
+                               etd->bLength, sizeof(*etd));
+                       break;
+               }
+               itr += etd->bLength;
+               bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
+                                 "%s (0x%02x/%02x) ",
+                                 wusb_et_name(etd->bEncryptionType),
+                                 etd->bEncryptionValue, etd->bAuthKeyIndex);
+               if (etd->bEncryptionType == USB_ENC_TYPE_CCM_1)
+                       ccm1_etd = etd;
+       }
+       /* This code only supports CCM1 as of now. */
+       /* FIXME: user has to choose which sec mode to use?
+        * In theory we want CCM */
+       if (ccm1_etd == NULL) {
+               dev_err(dev, "WUSB device doesn't support CCM1 encryption, "
+                       "can't use!\n");
+               result = -EINVAL;
+               goto out;
+       }
+       wusb_dev->ccm1_etd = *ccm1_etd;
+       dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n",
+               buf, wusb_et_name(ccm1_etd->bEncryptionType),
+               ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex);
+       result = 0;
+out:
+       kfree(secd);
+       return result;
+}
+
+void wusb_dev_sec_rm(struct wusb_dev *wusb_dev)
+{
+       /* Nothing so far */
+}
+
+/**
+ * Update the address of an unauthenticated WUSB device
+ *
+ * Once we have successfully authenticated, we take it to addr0 state
+ * and then to a normal address.
+ *
+ * Before the device's address (as known by it) was usb_dev->devnum |
+ * 0x80 (unauthenticated address). With this we update it to usb_dev->devnum.
+ */
+int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
+{
+       int result = -ENOMEM;
+       struct usb_device *usb_dev = wusb_dev->usb_dev;
+       struct device *dev = &usb_dev->dev;
+       u8 new_address = wusb_dev->addr & 0x7F;
+
+       /* Set address 0 */
+       result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                       USB_REQ_SET_ADDRESS,
+                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                        0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (result < 0) {
+               dev_err(dev, "auth failed: can't set address 0: %d\n",
+                       result);
+               goto error_addr0;
+       }
+       result = wusb_set_dev_addr(wusbhc, wusb_dev, 0);
+       if (result < 0)
+               goto error_addr0;
+       usb_set_device_state(usb_dev, USB_STATE_DEFAULT);
+       usb_ep0_reinit(usb_dev);
+
+       /* Set new (authenticated) address. */
+       result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+                       USB_REQ_SET_ADDRESS,
+                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                       new_address, 0, NULL, 0,
+                       USB_CTRL_SET_TIMEOUT);
+       if (result < 0) {
+               dev_err(dev, "auth failed: can't set address %u: %d\n",
+                       new_address, result);
+               goto error_addr;
+       }
+       result = wusb_set_dev_addr(wusbhc, wusb_dev, new_address);
+       if (result < 0)
+               goto error_addr;
+       usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
+       usb_ep0_reinit(usb_dev);
+       usb_dev->authenticated = 1;
+error_addr:
+error_addr0:
+       return result;
+}
+
+/*
+ *
+ *
+ */
+/* FIXME: split and cleanup */
+int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
+                           struct wusb_ckhdid *ck)
+{
+       int result = -ENOMEM;
+       struct usb_device *usb_dev = wusb_dev->usb_dev;
+       struct device *dev = &usb_dev->dev;
+       u32 tkid;
+       struct usb_handshake *hs;
+       struct aes_ccm_nonce ccm_n;
+       u8 mic[8];
+       struct wusb_keydvt_in keydvt_in;
+       struct wusb_keydvt_out keydvt_out;
+
+       hs = kcalloc(3, sizeof(hs[0]), GFP_KERNEL);
+       if (!hs)
+               goto error_kzalloc;
+
+       /* We need to turn encryption before beginning the 4way
+        * hshake (WUSB1.0[.3.2.2]) */
+       result = wusb_dev_set_encryption(usb_dev, 1);
+       if (result < 0)
+               goto error_dev_set_encryption;
+
+       tkid = wusbhc_next_tkid(wusbhc, wusb_dev);
+
+       hs[0].bMessageNumber = 1;
+       hs[0].bStatus = 0;
+       put_unaligned_le32(tkid, hs[0].tTKID);
+       hs[0].bReserved = 0;
+       memcpy(hs[0].CDID, &wusb_dev->cdid, sizeof(hs[0].CDID));
+       get_random_bytes(&hs[0].nonce, sizeof(hs[0].nonce));
+       memset(hs[0].MIC, 0, sizeof(hs[0].MIC)); /* Per WUSB1.0[T7-22] */
+
+       result = usb_control_msg(
+               usb_dev, usb_sndctrlpipe(usb_dev, 0),
+               USB_REQ_SET_HANDSHAKE,
+               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+               1, 0, &hs[0], sizeof(hs[0]), USB_CTRL_SET_TIMEOUT);
+       if (result < 0) {
+               dev_err(dev, "Handshake1: request failed: %d\n", result);
+               goto error_hs1;
+       }
+
+       /* Handshake 2, from the device -- need to verify fields */
+       result = usb_control_msg(
+               usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+               USB_REQ_GET_HANDSHAKE,
+               USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+               2, 0, &hs[1], sizeof(hs[1]), USB_CTRL_GET_TIMEOUT);
+       if (result < 0) {
+               dev_err(dev, "Handshake2: request failed: %d\n", result);
+               goto error_hs2;
+       }
+
+       result = -EINVAL;
+       if (hs[1].bMessageNumber != 2) {
+               dev_err(dev, "Handshake2 failed: bad message number %u\n",
+                       hs[1].bMessageNumber);
+               goto error_hs2;
+       }
+       if (hs[1].bStatus != 0) {
+               dev_err(dev, "Handshake2 failed: bad status %u\n",
+                       hs[1].bStatus);
+               goto error_hs2;
+       }
+       if (memcmp(hs[0].tTKID, hs[1].tTKID, sizeof(hs[0].tTKID))) {
+               dev_err(dev, "Handshake2 failed: TKID mismatch "
+                       "(#1 0x%02x%02x%02x vs #2 0x%02x%02x%02x)\n",
+                       hs[0].tTKID[0], hs[0].tTKID[1], hs[0].tTKID[2],
+                       hs[1].tTKID[0], hs[1].tTKID[1], hs[1].tTKID[2]);
+               goto error_hs2;
+       }
+       if (memcmp(hs[0].CDID, hs[1].CDID, sizeof(hs[0].CDID))) {
+               dev_err(dev, "Handshake2 failed: CDID mismatch\n");
+               goto error_hs2;
+       }
+
+       /* Setup the CCM nonce */
+       memset(&ccm_n.sfn, 0, sizeof(ccm_n.sfn)); /* Per WUSB1.0[6.5.2] */
+       put_unaligned_le32(tkid, ccm_n.tkid);
+       ccm_n.src_addr = wusbhc->uwb_rc->uwb_dev.dev_addr;
+       ccm_n.dest_addr.data[0] = wusb_dev->addr;
+       ccm_n.dest_addr.data[1] = 0;
+
+       /* Derive the KCK and PTK from CK, the CCM, H and D nonces */
+       memcpy(keydvt_in.hnonce, hs[0].nonce, sizeof(keydvt_in.hnonce));
+       memcpy(keydvt_in.dnonce, hs[1].nonce, sizeof(keydvt_in.dnonce));
+       result = wusb_key_derive(&keydvt_out, ck->data, &ccm_n, &keydvt_in);
+       if (result < 0) {
+               dev_err(dev, "Handshake2 failed: cannot derive keys: %d\n",
+                       result);
+               goto error_hs2;
+       }
+
+       /* Compute MIC and verify it */
+       result = wusb_oob_mic(mic, keydvt_out.kck, &ccm_n, &hs[1]);
+       if (result < 0) {
+               dev_err(dev, "Handshake2 failed: cannot compute MIC: %d\n",
+                       result);
+               goto error_hs2;
+       }
+
+       if (memcmp(hs[1].MIC, mic, sizeof(hs[1].MIC))) {
+               dev_err(dev, "Handshake2 failed: MIC mismatch\n");
+               goto error_hs2;
+       }
+
+       /* Send Handshake3 */
+       hs[2].bMessageNumber = 3;
+       hs[2].bStatus = 0;
+       put_unaligned_le32(tkid, hs[2].tTKID);
+       hs[2].bReserved = 0;
+       memcpy(hs[2].CDID, &wusb_dev->cdid, sizeof(hs[2].CDID));
+       memcpy(hs[2].nonce, hs[0].nonce, sizeof(hs[2].nonce));
+       result = wusb_oob_mic(hs[2].MIC, keydvt_out.kck, &ccm_n, &hs[2]);
+       if (result < 0) {
+               dev_err(dev, "Handshake3 failed: cannot compute MIC: %d\n",
+                       result);
+               goto error_hs2;
+       }
+
+       result = usb_control_msg(
+               usb_dev, usb_sndctrlpipe(usb_dev, 0),
+               USB_REQ_SET_HANDSHAKE,
+               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+               3, 0, &hs[2], sizeof(hs[2]), USB_CTRL_SET_TIMEOUT);
+       if (result < 0) {
+               dev_err(dev, "Handshake3: request failed: %d\n", result);
+               goto error_hs3;
+       }
+
+       result = wusbhc->set_ptk(wusbhc, wusb_dev->port_idx, tkid,
+                                keydvt_out.ptk, sizeof(keydvt_out.ptk));
+       if (result < 0)
+               goto error_wusbhc_set_ptk;
+
+       result = wusb_dev_set_gtk(wusbhc, wusb_dev);
+       if (result < 0) {
+               dev_err(dev, "Set GTK for device: request failed: %d\n",
+                       result);
+               goto error_wusbhc_set_gtk;
+       }
+
+       /* Update the device's address from unauth to auth */
+       if (usb_dev->authenticated == 0) {
+               result = wusb_dev_update_address(wusbhc, wusb_dev);
+               if (result < 0)
+                       goto error_dev_update_address;
+       }
+       result = 0;
+       dev_info(dev, "device authenticated\n");
+
+error_dev_update_address:
+error_wusbhc_set_gtk:
+error_wusbhc_set_ptk:
+error_hs3:
+error_hs2:
+error_hs1:
+       memset(hs, 0, 3*sizeof(hs[0]));
+       memzero_explicit(&keydvt_out, sizeof(keydvt_out));
+       memzero_explicit(&keydvt_in, sizeof(keydvt_in));
+       memzero_explicit(&ccm_n, sizeof(ccm_n));
+       memzero_explicit(mic, sizeof(mic));
+       if (result < 0)
+               wusb_dev_set_encryption(usb_dev, 0);
+error_dev_set_encryption:
+       kfree(hs);
+error_kzalloc:
+       return result;
+}
+
+/*
+ * Once all connected and authenticated devices have received the new
+ * GTK, switch the host to using it.
+ */
+static void wusbhc_gtk_rekey_work(struct work_struct *work)
+{
+       struct wusbhc *wusbhc = container_of(work,
+                                       struct wusbhc, gtk_rekey_work);
+       size_t key_size = sizeof(wusbhc->gtk.data);
+       int port_idx;
+       struct wusb_dev *wusb_dev, *wusb_dev_next;
+       LIST_HEAD(rekey_list);
+
+       mutex_lock(&wusbhc->mutex);
+       /* generate the new key */
+       wusbhc_generate_gtk(wusbhc);
+       /* roll the gtk index. */
+       wusbhc->gtk_index = (wusbhc->gtk_index + 1) % (WUSB_KEY_INDEX_MAX + 1);
+       /*
+        * Save all connected devices on a list while holding wusbhc->mutex and
+        * take a reference to each one.  Then submit the set key request to
+        * them after releasing the lock in order to avoid a deadlock.
+        */
+       for (port_idx = 0; port_idx < wusbhc->ports_max; port_idx++) {
+               wusb_dev = wusbhc->port[port_idx].wusb_dev;
+               if (!wusb_dev || !wusb_dev->usb_dev
+                       || !wusb_dev->usb_dev->authenticated)
+                       continue;
+
+               wusb_dev_get(wusb_dev);
+               list_add_tail(&wusb_dev->rekey_node, &rekey_list);
+       }
+       mutex_unlock(&wusbhc->mutex);
+
+       /* Submit the rekey requests without holding wusbhc->mutex. */
+       list_for_each_entry_safe(wusb_dev, wusb_dev_next, &rekey_list,
+               rekey_node) {
+               list_del_init(&wusb_dev->rekey_node);
+               dev_dbg(&wusb_dev->usb_dev->dev,
+                       "%s: rekey device at port %d\n",
+                       __func__, wusb_dev->port_idx);
+
+               if (wusb_dev_set_gtk(wusbhc, wusb_dev) < 0) {
+                       dev_err(&wusb_dev->usb_dev->dev,
+                               "%s: rekey device at port %d failed\n",
+                               __func__, wusb_dev->port_idx);
+               }
+               wusb_dev_put(wusb_dev);
+       }
+
+       /* Switch the host controller to use the new GTK. */
+       mutex_lock(&wusbhc->mutex);
+       wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
+               &wusbhc->gtk.descr.bKeyData, key_size);
+       mutex_unlock(&wusbhc->mutex);
+}
+
+/**
+ * wusbhc_gtk_rekey - generate and distribute a new GTK
+ * @wusbhc: the WUSB host controller
+ *
+ * Generate a new GTK and distribute it to all connected and
+ * authenticated devices.  When all devices have the new GTK, the host
+ * starts using it.
+ *
+ * This must be called after every device disconnect (see [WUSB]
+ * section 6.2.11.2).
+ */
+void wusbhc_gtk_rekey(struct wusbhc *wusbhc)
+{
+       /*
+        * We need to submit a URB to the downstream WUSB devices in order to
+        * change the group key.  This can't be done while holding the
+        * wusbhc->mutex since that is also taken in the urb_enqueue routine
+        * and will cause a deadlock.  Instead, queue a work item to do
+        * it when the lock is not held
+        */
+       queue_work(wusbhc->wq_security, &wusbhc->gtk_rekey_work);
+}
diff --git a/drivers/staging/wusbcore/wa-hc.c b/drivers/staging/wusbcore/wa-hc.c
new file mode 100644 (file)
index 0000000..6827075
--- /dev/null
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wire Adapter Host Controller Driver
+ * Common items to HWA and DWA based HCDs
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ */
+#include <linux/slab.h>
+#include <linux/module.h>
+#include "wusbhc.h"
+#include "wa-hc.h"
+
+/**
+ * Assumes
+ *
+ * wa->usb_dev and wa->usb_iface initialized and refcounted,
+ * wa->wa_descr initialized.
+ */
+int wa_create(struct wahc *wa, struct usb_interface *iface,
+       kernel_ulong_t quirks)
+{
+       int result;
+       struct device *dev = &iface->dev;
+
+       if (iface->cur_altsetting->desc.bNumEndpoints < 3)
+               return -ENODEV;
+
+       result = wa_rpipes_create(wa);
+       if (result < 0)
+               goto error_rpipes_create;
+       wa->quirks = quirks;
+       /* Fill up Data Transfer EP pointers */
+       wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc;
+       wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
+       wa->dti_buf_size = usb_endpoint_maxp(wa->dti_epd);
+       wa->dti_buf = kmalloc(wa->dti_buf_size, GFP_KERNEL);
+       if (wa->dti_buf == NULL) {
+               result = -ENOMEM;
+               goto error_dti_buf_alloc;
+       }
+       result = wa_nep_create(wa, iface);
+       if (result < 0) {
+               dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n",
+                       result);
+               goto error_nep_create;
+       }
+       return 0;
+
+error_nep_create:
+       kfree(wa->dti_buf);
+error_dti_buf_alloc:
+       wa_rpipes_destroy(wa);
+error_rpipes_create:
+       return result;
+}
+EXPORT_SYMBOL_GPL(wa_create);
+
+
+void __wa_destroy(struct wahc *wa)
+{
+       if (wa->dti_urb) {
+               usb_kill_urb(wa->dti_urb);
+               usb_put_urb(wa->dti_urb);
+       }
+       kfree(wa->dti_buf);
+       wa_nep_destroy(wa);
+       wa_rpipes_destroy(wa);
+}
+EXPORT_SYMBOL_GPL(__wa_destroy);
+
+/**
+ * wa_reset_all - reset the WA device
+ * @wa: the WA to be reset
+ *
+ * For HWAs the radio controller and all other PALs are also reset.
+ */
+void wa_reset_all(struct wahc *wa)
+{
+       /* FIXME: assuming HWA. */
+       wusbhc_reset_all(wa->wusb);
+}
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless USB Wire Adapter core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/wa-hc.h b/drivers/staging/wusbcore/wa-hc.h
new file mode 100644 (file)
index 0000000..5a38465
--- /dev/null
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * HWA Host Controller Driver
+ * Wire Adapter Control/Data Streaming Iface (WUSB1.0[8])
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This driver implements a USB Host Controller (struct usb_hcd) for a
+ * Wireless USB Host Controller based on the Wireless USB 1.0
+ * Host-Wire-Adapter specification (in layman terms, a USB-dongle that
+ * implements a Wireless USB host).
+ *
+ * Check out the Design-overview.txt file in the source documentation
+ * for other details on the implementation.
+ *
+ * Main blocks:
+ *
+ *  driver     glue with the driver API, workqueue daemon
+ *
+ *  lc         RC instance life cycle management (create, destroy...)
+ *
+ *  hcd        glue with the USB API Host Controller Interface API.
+ *
+ *  nep        Notification EndPoint management: collect notifications
+ *             and queue them with the workqueue daemon.
+ *
+ *             Handle notifications as coming from the NEP. Sends them
+ *             off others to their respective modules (eg: connect,
+ *             disconnect and reset go to devconnect).
+ *
+ *  rpipe      Remote Pipe management; rpipe is what we use to write
+ *             to an endpoint on a WUSB device that is connected to a
+ *             HWA RC.
+ *
+ *  xfer       Transfer management -- this is all the code that gets a
+ *             buffer and pushes it to a device (or viceversa). *
+ *
+ * Some day a lot of this code will be shared between this driver and
+ * the drivers for DWA (xfer, rpipe).
+ *
+ * All starts at driver.c:hwahc_probe(), when one of this guys is
+ * connected. hwahc_disconnect() stops it.
+ *
+ * During operation, the main driver is devices connecting or
+ * disconnecting. They cause the HWA RC to send notifications into
+ * nep.c:hwahc_nep_cb() that will dispatch them to
+ * notif.c:wa_notif_dispatch(). From there they will fan to cause
+ * device connects, disconnects, etc.
+ *
+ * Note much of the activity is difficult to follow. For example a
+ * device connect goes to devconnect, which will cause the "fake" root
+ * hub port to show a connect and stop there. Then hub_wq will notice
+ * and call into the rh.c:hwahc_rc_port_reset() code to authenticate
+ * the device (and this might require user intervention) and enable
+ * the port.
+ *
+ * We also have a timer workqueue going from devconnect.c that
+ * schedules in hwahc_devconnect_create().
+ *
+ * The rest of the traffic is in the usual entry points of a USB HCD,
+ * which are hooked up in driver.c:hwahc_rc_driver, and defined in
+ * hcd.c.
+ */
+
+#ifndef __HWAHC_INTERNAL_H__
+#define __HWAHC_INTERNAL_H__
+
+#include <linux/completion.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include "../uwb/uwb.h"
+#include "include/wusb.h"
+#include "include/wusb-wa.h"
+
+struct wusbhc;
+struct wahc;
+extern void wa_urb_enqueue_run(struct work_struct *ws);
+extern void wa_process_errored_transfers_run(struct work_struct *ws);
+
+/**
+ * RPipe instance
+ *
+ * @descr's fields are kept in LE, as we need to send it back and
+ * forth.
+ *
+ * @wa is referenced when set
+ *
+ * @segs_available is the number of requests segments that still can
+ *                 be submitted to the controller without overloading
+ *                 it. It is initialized to descr->wRequests when
+ *                 aiming.
+ *
+ * A rpipe supports a max of descr->wRequests at the same time; before
+ * submitting seg_lock has to be taken. If segs_avail > 0, then we can
+ * submit; if not, we have to queue them.
+ */
+struct wa_rpipe {
+       struct kref refcnt;
+       struct usb_rpipe_descriptor descr;
+       struct usb_host_endpoint *ep;
+       struct wahc *wa;
+       spinlock_t seg_lock;
+       struct list_head seg_list;
+       struct list_head list_node;
+       atomic_t segs_available;
+       u8 buffer[1];   /* For reads/writes on USB */
+};
+
+
+enum wa_dti_state {
+       WA_DTI_TRANSFER_RESULT_PENDING,
+       WA_DTI_ISOC_PACKET_STATUS_PENDING,
+       WA_DTI_BUF_IN_DATA_PENDING
+};
+
+enum wa_quirks {
+       /*
+        * The Alereon HWA expects the data frames in isochronous transfer
+        * requests to be concatenated and not sent as separate packets.
+        */
+       WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC      = 0x01,
+       /*
+        * The Alereon HWA can be instructed to not send transfer notifications
+        * as an optimization.
+        */
+       WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS       = 0x02,
+};
+
+enum wa_vendor_specific_requests {
+       WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS = 0x4C,
+       WA_REQ_ALEREON_FEATURE_SET = 0x01,
+       WA_REQ_ALEREON_FEATURE_CLEAR = 0x00,
+};
+
+#define WA_MAX_BUF_IN_URBS     4
+/**
+ * Instance of a HWA Host Controller
+ *
+ * Except where a more specific lock/mutex applies or atomic, all
+ * fields protected by @mutex.
+ *
+ * @wa_descr  Can be accessed without locking because it is in
+ *            the same area where the device descriptors were
+ *            read, so it is guaranteed to exist unmodified while
+ *            the device exists.
+ *
+ *            Endianess has been converted to CPU's.
+ *
+ * @nep_* can be accessed without locking as its processing is
+ *        serialized; we submit a NEP URB and it comes to
+ *        hwahc_nep_cb(), which won't issue another URB until it is
+ *        done processing it.
+ *
+ * @xfer_list:
+ *
+ *   List of active transfers to verify existence from a xfer id
+ *   gotten from the xfer result message. Can't use urb->list because
+ *   it goes by endpoint, and we don't know the endpoint at the time
+ *   when we get the xfer result message. We can't really rely on the
+ *   pointer (will have to change for 64 bits) as the xfer id is 32 bits.
+ *
+ * @xfer_delayed_list:   List of transfers that need to be started
+ *                       (with a workqueue, because they were
+ *                       submitted from an atomic context).
+ *
+ * FIXME: this needs to be layered up: a wusbhc layer (for sharing
+ *        commonalities with WHCI), a wa layer (for sharing
+ *        commonalities with DWA-RC).
+ */
+struct wahc {
+       struct usb_device *usb_dev;
+       struct usb_interface *usb_iface;
+
+       /* HC to deliver notifications */
+       union {
+               struct wusbhc *wusb;
+               struct dwahc *dwa;
+       };
+
+       const struct usb_endpoint_descriptor *dto_epd, *dti_epd;
+       const struct usb_wa_descriptor *wa_descr;
+
+       struct urb *nep_urb;            /* Notification EndPoint [lockless] */
+       struct edc nep_edc;
+       void *nep_buffer;
+       size_t nep_buffer_size;
+
+       atomic_t notifs_queued;
+
+       u16 rpipes;
+       unsigned long *rpipe_bm;        /* rpipe usage bitmap */
+       struct list_head rpipe_delayed_list;    /* delayed RPIPES. */
+       spinlock_t rpipe_lock;  /* protect rpipe_bm and delayed list */
+       struct mutex rpipe_mutex;       /* assigning resources to endpoints */
+
+       /*
+        * dti_state is used to track the state of the dti_urb. When dti_state
+        * is WA_DTI_ISOC_PACKET_STATUS_PENDING, dti_isoc_xfer_in_progress and
+        * dti_isoc_xfer_seg identify which xfer the incoming isoc packet
+        * status refers to.
+        */
+       enum wa_dti_state dti_state;
+       u32 dti_isoc_xfer_in_progress;
+       u8  dti_isoc_xfer_seg;
+       struct urb *dti_urb;            /* URB for reading xfer results */
+                                       /* URBs for reading data in */
+       struct urb buf_in_urbs[WA_MAX_BUF_IN_URBS];
+       int active_buf_in_urbs;         /* number of buf_in_urbs active. */
+       struct edc dti_edc;             /* DTI error density counter */
+       void *dti_buf;
+       size_t dti_buf_size;
+
+       unsigned long dto_in_use;       /* protect dto endoint serialization */
+
+       s32 status;                     /* For reading status */
+
+       struct list_head xfer_list;
+       struct list_head xfer_delayed_list;
+       struct list_head xfer_errored_list;
+       /*
+        * lock for the above xfer lists.  Can be taken while a xfer->lock is
+        * held but not in the reverse order.
+        */
+       spinlock_t xfer_list_lock;
+       struct work_struct xfer_enqueue_work;
+       struct work_struct xfer_error_work;
+       atomic_t xfer_id_count;
+
+       kernel_ulong_t  quirks;
+};
+
+
+extern int wa_create(struct wahc *wa, struct usb_interface *iface,
+       kernel_ulong_t);
+extern void __wa_destroy(struct wahc *wa);
+extern int wa_dti_start(struct wahc *wa);
+void wa_reset_all(struct wahc *wa);
+
+
+/* Miscellaneous constants */
+enum {
+       /** Max number of EPROTO errors we tolerate on the NEP in a
+        * period of time */
+       HWAHC_EPROTO_MAX = 16,
+       /** Period of time for EPROTO errors (in jiffies) */
+       HWAHC_EPROTO_PERIOD = 4 * HZ,
+};
+
+
+/* Notification endpoint handling */
+extern int wa_nep_create(struct wahc *, struct usb_interface *);
+extern void wa_nep_destroy(struct wahc *);
+
+static inline int wa_nep_arm(struct wahc *wa, gfp_t gfp_mask)
+{
+       struct urb *urb = wa->nep_urb;
+       urb->transfer_buffer = wa->nep_buffer;
+       urb->transfer_buffer_length = wa->nep_buffer_size;
+       return usb_submit_urb(urb, gfp_mask);
+}
+
+static inline void wa_nep_disarm(struct wahc *wa)
+{
+       usb_kill_urb(wa->nep_urb);
+}
+
+
+/* RPipes */
+static inline void wa_rpipe_init(struct wahc *wa)
+{
+       INIT_LIST_HEAD(&wa->rpipe_delayed_list);
+       spin_lock_init(&wa->rpipe_lock);
+       mutex_init(&wa->rpipe_mutex);
+}
+
+static inline void wa_init(struct wahc *wa)
+{
+       int index;
+
+       edc_init(&wa->nep_edc);
+       atomic_set(&wa->notifs_queued, 0);
+       wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
+       wa_rpipe_init(wa);
+       edc_init(&wa->dti_edc);
+       INIT_LIST_HEAD(&wa->xfer_list);
+       INIT_LIST_HEAD(&wa->xfer_delayed_list);
+       INIT_LIST_HEAD(&wa->xfer_errored_list);
+       spin_lock_init(&wa->xfer_list_lock);
+       INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run);
+       INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run);
+       wa->dto_in_use = 0;
+       atomic_set(&wa->xfer_id_count, 1);
+       /* init the buf in URBs */
+       for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index)
+               usb_init_urb(&(wa->buf_in_urbs[index]));
+       wa->active_buf_in_urbs = 0;
+}
+
+/**
+ * Destroy a pipe (when refcount drops to zero)
+ *
+ * Assumes it has been moved to the "QUIESCING" state.
+ */
+struct wa_xfer;
+extern void rpipe_destroy(struct kref *_rpipe);
+static inline
+void __rpipe_get(struct wa_rpipe *rpipe)
+{
+       kref_get(&rpipe->refcnt);
+}
+extern int rpipe_get_by_ep(struct wahc *, struct usb_host_endpoint *,
+                          struct urb *, gfp_t);
+static inline void rpipe_put(struct wa_rpipe *rpipe)
+{
+       kref_put(&rpipe->refcnt, rpipe_destroy);
+
+}
+extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *);
+extern void rpipe_clear_feature_stalled(struct wahc *,
+                       struct usb_host_endpoint *);
+extern int wa_rpipes_create(struct wahc *);
+extern void wa_rpipes_destroy(struct wahc *);
+static inline void rpipe_avail_dec(struct wa_rpipe *rpipe)
+{
+       atomic_dec(&rpipe->segs_available);
+}
+
+/**
+ * Returns true if the rpipe is ready to submit more segments.
+ */
+static inline int rpipe_avail_inc(struct wa_rpipe *rpipe)
+{
+       return atomic_inc_return(&rpipe->segs_available) > 0
+               && !list_empty(&rpipe->seg_list);
+}
+
+
+/* Transferring data */
+extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *,
+                         struct urb *, gfp_t);
+extern int wa_urb_dequeue(struct wahc *, struct urb *, int);
+extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *);
+
+
+/* Misc
+ *
+ * FIXME: Refcounting for the actual @hwahc object is not correct; I
+ *        mean, this should be refcounting on the HCD underneath, but
+ *        it is not. In any case, the semantics for HCD refcounting
+ *        are *weird*...on refcount reaching zero it just frees
+ *        it...no RC specific function is called...unless I miss
+ *        something.
+ *
+ * FIXME: has to go away in favour of a 'struct' hcd based solution
+ */
+static inline struct wahc *wa_get(struct wahc *wa)
+{
+       usb_get_intf(wa->usb_iface);
+       return wa;
+}
+
+static inline void wa_put(struct wahc *wa)
+{
+       usb_put_intf(wa->usb_iface);
+}
+
+
+static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature)
+{
+       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       op ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       feature,
+                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+                       NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
+
+static inline int __wa_set_feature(struct wahc *wa, u16 feature)
+{
+       return  __wa_feature(wa, 1, feature);
+}
+
+
+static inline int __wa_clear_feature(struct wahc *wa, u16 feature)
+{
+       return __wa_feature(wa, 0, feature);
+}
+
+
+/**
+ * Return the status of a Wire Adapter
+ *
+ * @wa:                Wire Adapter instance
+ * @returns     < 0 errno code on error, or status bitmap as described
+ *              in WUSB1.0[8.3.1.6].
+ *
+ * NOTE: need malloc, some arches don't take USB from the stack
+ */
+static inline
+s32 __wa_get_status(struct wahc *wa)
+{
+       s32 result;
+       result = usb_control_msg(
+               wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
+               USB_REQ_GET_STATUS,
+               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+               0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
+               &wa->status, sizeof(wa->status), USB_CTRL_GET_TIMEOUT);
+       if (result >= 0)
+               result = wa->status;
+       return result;
+}
+
+
+/**
+ * Waits until the Wire Adapter's status matches @mask/@value
+ *
+ * @wa:                Wire Adapter instance.
+ * @returns     < 0 errno code on error, otherwise status.
+ *
+ * Loop until the WAs status matches the mask and value (status & mask
+ * == value). Timeout if it doesn't happen.
+ *
+ * FIXME: is there an official specification on how long status
+ *        changes can take?
+ */
+static inline s32 __wa_wait_status(struct wahc *wa, u32 mask, u32 value)
+{
+       s32 result;
+       unsigned loops = 10;
+       do {
+               msleep(50);
+               result = __wa_get_status(wa);
+               if ((result & mask) == value)
+                       break;
+               if (loops-- == 0) {
+                       result = -ETIMEDOUT;
+                       break;
+               }
+       } while (result >= 0);
+       return result;
+}
+
+
+/** Command @hwahc to stop, @returns 0 if ok, < 0 errno code on error */
+static inline int __wa_stop(struct wahc *wa)
+{
+       int result;
+       struct device *dev = &wa->usb_iface->dev;
+
+       result = __wa_clear_feature(wa, WA_ENABLE);
+       if (result < 0 && result != -ENODEV) {
+               dev_err(dev, "error commanding HC to stop: %d\n", result);
+               goto out;
+       }
+       result = __wa_wait_status(wa, WA_ENABLE, 0);
+       if (result < 0 && result != -ENODEV)
+               dev_err(dev, "error waiting for HC to stop: %d\n", result);
+out:
+       return 0;
+}
+
+
+#endif /* #ifndef __HWAHC_INTERNAL_H__ */
diff --git a/drivers/staging/wusbcore/wa-nep.c b/drivers/staging/wusbcore/wa-nep.c
new file mode 100644 (file)
index 0000000..5f0656d
--- /dev/null
@@ -0,0 +1,289 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
+ * Notification EndPoint support
+ *
+ * Copyright (C) 2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This part takes care of getting the notification from the hw
+ * only and dispatching through wusbwad into
+ * wa_notif_dispatch. Handling is done there.
+ *
+ * WA notifications are limited in size; most of them are three or
+ * four bytes long, and the longest is the HWA Device Notification,
+ * which would not exceed 38 bytes (DNs are limited in payload to 32
+ * bytes plus 3 bytes header (WUSB1.0[7.6p2]), plus 3 bytes HWA
+ * header (WUSB1.0[8.5.4.2]).
+ *
+ * It is not clear if more than one Device Notification can be packed
+ * in a HWA Notification, I assume no because of the wording in
+ * WUSB1.0[8.5.4.2]. In any case, the bigger any notification could
+ * get is 256 bytes (as the bLength field is a byte).
+ *
+ * So what we do is we have this buffer and read into it; when a
+ * notification arrives we schedule work to a specific, single thread
+ * workqueue (so notifications are serialized) and copy the
+ * notification data. After scheduling the work, we rearm the read from
+ * the notification endpoint.
+ *
+ * Entry points here are:
+ *
+ * wa_nep_[create|destroy]()   To initialize/release this subsystem
+ *
+ * wa_nep_cb()                 Callback for the notification
+ *                                endpoint; when data is ready, this
+ *                                does the dispatching.
+ */
+#include <linux/workqueue.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+
+#include "wa-hc.h"
+#include "wusbhc.h"
+
+/* Structure for queueing notifications to the workqueue */
+struct wa_notif_work {
+       struct work_struct work;
+       struct wahc *wa;
+       size_t size;
+       u8 data[];
+};
+
+/*
+ * Process incoming notifications from the WA's Notification EndPoint
+ * [the wuswad daemon, basically]
+ *
+ * @_nw:       Pointer to a descriptor which has the pointer to the
+ *             @wa, the size of the buffer and the work queue
+ *             structure (so we can free all when done).
+ * @returns     0 if ok, < 0 errno code on error.
+ *
+ * All notifications follow the same format; they need to start with a
+ * 'struct wa_notif_hdr' header, so it is easy to parse through
+ * them. We just break the buffer in individual notifications (the
+ * standard doesn't say if it can be done or is forbidden, so we are
+ * cautious) and dispatch each.
+ *
+ * So the handling layers are is:
+ *
+ *   WA specific notification (from NEP)
+ *      Device Notification Received -> wa_handle_notif_dn()
+ *        WUSB Device notification generic handling
+ *      BPST Adjustment -> wa_handle_notif_bpst_adj()
+ *      ... -> ...
+ *
+ * @wa has to be referenced
+ */
+static void wa_notif_dispatch(struct work_struct *ws)
+{
+       void *itr;
+       u8 missing = 0;
+       struct wa_notif_work *nw = container_of(ws, struct wa_notif_work,
+                                               work);
+       struct wahc *wa = nw->wa;
+       struct wa_notif_hdr *notif_hdr;
+       size_t size;
+
+       struct device *dev = &wa->usb_iface->dev;
+
+#if 0
+       /* FIXME: need to check for this??? */
+       if (usb_hcd->state == HC_STATE_QUIESCING)       /* Going down? */
+               goto out;                               /* screw it */
+#endif
+       atomic_dec(&wa->notifs_queued);         /* Throttling ctl */
+       size = nw->size;
+       itr = nw->data;
+
+       while (size) {
+               if (size < sizeof(*notif_hdr)) {
+                       missing = sizeof(*notif_hdr) - size;
+                       goto exhausted_buffer;
+               }
+               notif_hdr = itr;
+               if (size < notif_hdr->bLength)
+                       goto exhausted_buffer;
+               itr += notif_hdr->bLength;
+               size -= notif_hdr->bLength;
+               /* Dispatch the notification [don't use itr or size!] */
+               switch (notif_hdr->bNotifyType) {
+               case HWA_NOTIF_DN: {
+                       struct hwa_notif_dn *hwa_dn;
+                       hwa_dn = container_of(notif_hdr, struct hwa_notif_dn,
+                                             hdr);
+                       wusbhc_handle_dn(wa->wusb, hwa_dn->bSourceDeviceAddr,
+                                        hwa_dn->dndata,
+                                        notif_hdr->bLength - sizeof(*hwa_dn));
+                       break;
+               }
+               case WA_NOTIF_TRANSFER:
+                       wa_handle_notif_xfer(wa, notif_hdr);
+                       break;
+               case HWA_NOTIF_BPST_ADJ:
+                       break; /* no action needed for BPST ADJ. */
+               case DWA_NOTIF_RWAKE:
+               case DWA_NOTIF_PORTSTATUS:
+                       /* FIXME: unimplemented WA NOTIFs */
+                       /* fallthru */
+               default:
+                       dev_err(dev, "HWA: unknown notification 0x%x, "
+                               "%zu bytes; discarding\n",
+                               notif_hdr->bNotifyType,
+                               (size_t)notif_hdr->bLength);
+                       break;
+               }
+       }
+out:
+       wa_put(wa);
+       kfree(nw);
+       return;
+
+       /* THIS SHOULD NOT HAPPEN
+        *
+        * Buffer exahusted with partial data remaining; just warn and
+        * discard the data, as this should not happen.
+        */
+exhausted_buffer:
+       dev_warn(dev, "HWA: device sent short notification, "
+                "%d bytes missing; discarding %d bytes.\n",
+                missing, (int)size);
+       goto out;
+}
+
+/*
+ * Deliver incoming WA notifications to the wusbwa workqueue
+ *
+ * @wa:        Pointer the Wire Adapter Controller Data Streaming
+ *              instance (part of an 'struct usb_hcd').
+ * @size:       Size of the received buffer
+ * @returns     0 if ok, < 0 errno code on error.
+ *
+ * The input buffer is @wa->nep_buffer, with @size bytes
+ * (guaranteed to fit in the allocated space,
+ * @wa->nep_buffer_size).
+ */
+static int wa_nep_queue(struct wahc *wa, size_t size)
+{
+       int result = 0;
+       struct device *dev = &wa->usb_iface->dev;
+       struct wa_notif_work *nw;
+
+       /* dev_fnstart(dev, "(wa %p, size %zu)\n", wa, size); */
+       BUG_ON(size > wa->nep_buffer_size);
+       if (size == 0)
+               goto out;
+       if (atomic_read(&wa->notifs_queued) > 200) {
+               if (printk_ratelimit())
+                       dev_err(dev, "Too many notifications queued, "
+                               "throttling back\n");
+               goto out;
+       }
+       nw = kzalloc(sizeof(*nw) + size, GFP_ATOMIC);
+       if (nw == NULL) {
+               if (printk_ratelimit())
+                       dev_err(dev, "No memory to queue notification\n");
+               result = -ENOMEM;
+               goto out;
+       }
+       INIT_WORK(&nw->work, wa_notif_dispatch);
+       nw->wa = wa_get(wa);
+       nw->size = size;
+       memcpy(nw->data, wa->nep_buffer, size);
+       atomic_inc(&wa->notifs_queued);         /* Throttling ctl */
+       queue_work(wusbd, &nw->work);
+out:
+       /* dev_fnend(dev, "(wa %p, size %zu) = result\n", wa, size, result); */
+       return result;
+}
+
+/*
+ * Callback for the notification event endpoint
+ *
+ * Check's that everything is fine and then passes the data to be
+ * queued to the workqueue.
+ */
+static void wa_nep_cb(struct urb *urb)
+{
+       int result;
+       struct wahc *wa = urb->context;
+       struct device *dev = &wa->usb_iface->dev;
+
+       switch (result = urb->status) {
+       case 0:
+               result = wa_nep_queue(wa, urb->actual_length);
+               if (result < 0)
+                       dev_err(dev, "NEP: unable to process notification(s): "
+                               "%d\n", result);
+               break;
+       case -ECONNRESET:       /* Not an error, but a controlled situation; */
+       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
+       case -ESHUTDOWN:
+               dev_dbg(dev, "NEP: going down %d\n", urb->status);
+               goto out;
+       default:        /* On general errors, we retry unless it gets ugly */
+               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+                           EDC_ERROR_TIMEFRAME)) {
+                       dev_err(dev, "NEP: URB max acceptable errors "
+                               "exceeded, resetting device\n");
+                       wa_reset_all(wa);
+                       goto out;
+               }
+               dev_err(dev, "NEP: URB error %d\n", urb->status);
+       }
+       result = wa_nep_arm(wa, GFP_ATOMIC);
+       if (result < 0) {
+               dev_err(dev, "NEP: cannot submit URB: %d\n", result);
+               wa_reset_all(wa);
+       }
+out:
+       return;
+}
+
+/*
+ * Initialize @wa's notification and event's endpoint stuff
+ *
+ * This includes the allocating the read buffer, the context ID
+ * allocation bitmap, the URB and submitting the URB.
+ */
+int wa_nep_create(struct wahc *wa, struct usb_interface *iface)
+{
+       int result;
+       struct usb_endpoint_descriptor *epd;
+       struct usb_device *usb_dev = interface_to_usbdev(iface);
+       struct device *dev = &iface->dev;
+
+       edc_init(&wa->nep_edc);
+       epd = &iface->cur_altsetting->endpoint[0].desc;
+       wa->nep_buffer_size = 1024;
+       wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL);
+       if (!wa->nep_buffer)
+               goto error_nep_buffer;
+       wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (wa->nep_urb == NULL)
+               goto error_urb_alloc;
+       usb_fill_int_urb(wa->nep_urb, usb_dev,
+                        usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
+                        wa->nep_buffer, wa->nep_buffer_size,
+                        wa_nep_cb, wa, epd->bInterval);
+       result = wa_nep_arm(wa, GFP_KERNEL);
+       if (result < 0) {
+               dev_err(dev, "Cannot submit notification URB: %d\n", result);
+               goto error_nep_arm;
+       }
+       return 0;
+
+error_nep_arm:
+       usb_free_urb(wa->nep_urb);
+error_urb_alloc:
+       kfree(wa->nep_buffer);
+error_nep_buffer:
+       return -ENOMEM;
+}
+
+void wa_nep_destroy(struct wahc *wa)
+{
+       wa_nep_disarm(wa);
+       usb_free_urb(wa->nep_urb);
+       kfree(wa->nep_buffer);
+}
diff --git a/drivers/staging/wusbcore/wa-rpipe.c b/drivers/staging/wusbcore/wa-rpipe.c
new file mode 100644 (file)
index 0000000..a5734cb
--- /dev/null
@@ -0,0 +1,539 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB Wire Adapter
+ * rpipe management
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * FIXME: docs
+ *
+ * RPIPE
+ *
+ *   Targeted at different downstream endpoints
+ *
+ *   Descriptor: use to config the remote pipe.
+ *
+ *   The number of blocks could be dynamic (wBlocks in descriptor is
+ *   0)--need to schedule them then.
+ *
+ * Each bit in wa->rpipe_bm represents if an rpipe is being used or
+ * not. Rpipes are represented with a 'struct wa_rpipe' that is
+ * attached to the hcpriv member of a 'struct usb_host_endpoint'.
+ *
+ * When you need to xfer data to an endpoint, you get an rpipe for it
+ * with wa_ep_rpipe_get(), which gives you a reference to the rpipe
+ * and keeps a single one (the first one) with the endpoint. When you
+ * are done transferring, you drop that reference. At the end the
+ * rpipe is always allocated and bound to the endpoint. There it might
+ * be recycled when not used.
+ *
+ * Addresses:
+ *
+ *  We use a 1:1 mapping mechanism between port address (0 based
+ *  index, actually) and the address. The USB stack knows about this.
+ *
+ *  USB Stack port number    4 (1 based)
+ *  WUSB code port index     3 (0 based)
+ *  USB Address             5 (2 based -- 0 is for default, 1 for root hub)
+ *
+ *  Now, because we don't use the concept as default address exactly
+ *  like the (wired) USB code does, we need to kind of skip it. So we
+ *  never take addresses from the urb->pipe, but from the
+ *  urb->dev->devnum, to make sure that we always have the right
+ *  destination address.
+ */
+#include <linux/atomic.h>
+#include <linux/bitmap.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include "wusbhc.h"
+#include "wa-hc.h"
+
+static int __rpipe_get_descr(struct wahc *wa,
+                            struct usb_rpipe_descriptor *descr, u16 index)
+{
+       ssize_t result;
+       struct device *dev = &wa->usb_iface->dev;
+
+       /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor()
+        * function because the arguments are different.
+        */
+       result = usb_control_msg(
+               wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
+               USB_REQ_GET_DESCRIPTOR,
+               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+               USB_DT_RPIPE<<8, index, descr, sizeof(*descr),
+               USB_CTRL_GET_TIMEOUT);
+       if (result < 0) {
+               dev_err(dev, "rpipe %u: get descriptor failed: %d\n",
+                       index, (int)result);
+               goto error;
+       }
+       if (result < sizeof(*descr)) {
+               dev_err(dev, "rpipe %u: got short descriptor "
+                       "(%zd vs %zd bytes needed)\n",
+                       index, result, sizeof(*descr));
+               result = -EINVAL;
+               goto error;
+       }
+       result = 0;
+
+error:
+       return result;
+}
+
+/*
+ *
+ * The descriptor is assumed to be properly initialized (ie: you got
+ * it through __rpipe_get_descr()).
+ */
+static int __rpipe_set_descr(struct wahc *wa,
+                            struct usb_rpipe_descriptor *descr, u16 index)
+{
+       ssize_t result;
+       struct device *dev = &wa->usb_iface->dev;
+
+       /* we cannot use the usb_get_descriptor() function because the
+        * arguments are different.
+        */
+       result = usb_control_msg(
+               wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+               USB_REQ_SET_DESCRIPTOR,
+               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+               USB_DT_RPIPE<<8, index, descr, sizeof(*descr),
+               USB_CTRL_SET_TIMEOUT);
+       if (result < 0) {
+               dev_err(dev, "rpipe %u: set descriptor failed: %d\n",
+                       index, (int)result);
+               goto error;
+       }
+       if (result < sizeof(*descr)) {
+               dev_err(dev, "rpipe %u: sent short descriptor "
+                       "(%zd vs %zd bytes required)\n",
+                       index, result, sizeof(*descr));
+               result = -EINVAL;
+               goto error;
+       }
+       result = 0;
+
+error:
+       return result;
+
+}
+
+static void rpipe_init(struct wa_rpipe *rpipe)
+{
+       kref_init(&rpipe->refcnt);
+       spin_lock_init(&rpipe->seg_lock);
+       INIT_LIST_HEAD(&rpipe->seg_list);
+       INIT_LIST_HEAD(&rpipe->list_node);
+}
+
+static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&wa->rpipe_lock, flags);
+       rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx);
+       if (rpipe_idx < wa->rpipes)
+               set_bit(rpipe_idx, wa->rpipe_bm);
+       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
+
+       return rpipe_idx;
+}
+
+static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&wa->rpipe_lock, flags);
+       clear_bit(rpipe_idx, wa->rpipe_bm);
+       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
+}
+
+void rpipe_destroy(struct kref *_rpipe)
+{
+       struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt);
+       u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+
+       if (rpipe->ep)
+               rpipe->ep->hcpriv = NULL;
+       rpipe_put_idx(rpipe->wa, index);
+       wa_put(rpipe->wa);
+       kfree(rpipe);
+}
+EXPORT_SYMBOL_GPL(rpipe_destroy);
+
+/*
+ * Locate an idle rpipe, create an structure for it and return it
+ *
+ * @wa   is referenced and unlocked
+ * @crs   enum rpipe_attr, required endpoint characteristics
+ *
+ * The rpipe can be used only sequentially (not in parallel).
+ *
+ * The rpipe is moved into the "ready" state.
+ */
+static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs,
+                         gfp_t gfp)
+{
+       int result;
+       unsigned rpipe_idx;
+       struct wa_rpipe *rpipe;
+       struct device *dev = &wa->usb_iface->dev;
+
+       rpipe = kzalloc(sizeof(*rpipe), gfp);
+       if (rpipe == NULL)
+               return -ENOMEM;
+       rpipe_init(rpipe);
+
+       /* Look for an idle pipe */
+       for (rpipe_idx = 0; rpipe_idx < wa->rpipes; rpipe_idx++) {
+               rpipe_idx = rpipe_get_idx(wa, rpipe_idx);
+               if (rpipe_idx >= wa->rpipes)    /* no more pipes :( */
+                       break;
+               result =  __rpipe_get_descr(wa, &rpipe->descr, rpipe_idx);
+               if (result < 0)
+                       dev_err(dev, "Can't get descriptor for rpipe %u: %d\n",
+                               rpipe_idx, result);
+               else if ((rpipe->descr.bmCharacteristics & crs) != 0)
+                       goto found;
+               rpipe_put_idx(wa, rpipe_idx);
+       }
+       *prpipe = NULL;
+       kfree(rpipe);
+       return -ENXIO;
+
+found:
+       set_bit(rpipe_idx, wa->rpipe_bm);
+       rpipe->wa = wa_get(wa);
+       *prpipe = rpipe;
+       return 0;
+}
+
+static int __rpipe_reset(struct wahc *wa, unsigned index)
+{
+       int result;
+       struct device *dev = &wa->usb_iface->dev;
+
+       result = usb_control_msg(
+               wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+               USB_REQ_RPIPE_RESET,
+               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+               0, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (result < 0)
+               dev_err(dev, "rpipe %u: reset failed: %d\n",
+                       index, result);
+       return result;
+}
+
+/*
+ * Fake companion descriptor for ep0
+ *
+ * See WUSB1.0[7.4.4], most of this is zero for bulk/int/ctl
+ */
+static struct usb_wireless_ep_comp_descriptor epc0 = {
+       .bLength = sizeof(epc0),
+       .bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP,
+       .bMaxBurst = 1,
+       .bMaxSequence = 2,
+};
+
+/*
+ * Look for EP companion descriptor
+ *
+ * Get there, look for Inara in the endpoint's extra descriptors
+ */
+static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find(
+               struct device *dev, struct usb_host_endpoint *ep)
+{
+       void *itr;
+       size_t itr_size;
+       struct usb_descriptor_header *hdr;
+       struct usb_wireless_ep_comp_descriptor *epcd;
+
+       if (ep->desc.bEndpointAddress == 0) {
+               epcd = &epc0;
+               goto out;
+       }
+       itr = ep->extra;
+       itr_size = ep->extralen;
+       epcd = NULL;
+       while (itr_size > 0) {
+               if (itr_size < sizeof(*hdr)) {
+                       dev_err(dev, "HW Bug? ep 0x%02x: extra descriptors "
+                               "at offset %zu: only %zu bytes left\n",
+                               ep->desc.bEndpointAddress,
+                               itr - (void *) ep->extra, itr_size);
+                       break;
+               }
+               hdr = itr;
+               if (hdr->bDescriptorType == USB_DT_WIRELESS_ENDPOINT_COMP) {
+                       epcd = itr;
+                       break;
+               }
+               if (hdr->bLength > itr_size) {
+                       dev_err(dev, "HW Bug? ep 0x%02x: extra descriptor "
+                               "at offset %zu (type 0x%02x) "
+                               "length %d but only %zu bytes left\n",
+                               ep->desc.bEndpointAddress,
+                               itr - (void *) ep->extra, hdr->bDescriptorType,
+                               hdr->bLength, itr_size);
+                       break;
+               }
+               itr += hdr->bLength;
+               itr_size -= hdr->bLength;
+       }
+out:
+       return epcd;
+}
+
+/*
+ * Aim an rpipe to its device & endpoint destination
+ *
+ * Make sure we change the address to unauthenticated if the device
+ * is WUSB and it is not authenticated.
+ */
+static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,
+                    struct usb_host_endpoint *ep, struct urb *urb, gfp_t gfp)
+{
+       int result = -ENOMSG;   /* better code for lack of companion? */
+       struct device *dev = &wa->usb_iface->dev;
+       struct usb_device *usb_dev = urb->dev;
+       struct usb_wireless_ep_comp_descriptor *epcd;
+       u32 ack_window, epcd_max_sequence;
+       u8 unauth;
+
+       epcd = rpipe_epc_find(dev, ep);
+       if (epcd == NULL) {
+               dev_err(dev, "ep 0x%02x: can't find companion descriptor\n",
+                       ep->desc.bEndpointAddress);
+               goto error;
+       }
+       unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0;
+       __rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex));
+       atomic_set(&rpipe->segs_available,
+               le16_to_cpu(rpipe->descr.wRequests));
+       /* FIXME: block allocation system; request with queuing and timeout */
+       /* FIXME: compute so seg_size > ep->maxpktsize */
+       rpipe->descr.wBlocks = cpu_to_le16(16);         /* given */
+       /* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */
+       if (usb_endpoint_xfer_isoc(&ep->desc))
+               rpipe->descr.wMaxPacketSize = epcd->wOverTheAirPacketSize;
+       else
+               rpipe->descr.wMaxPacketSize = ep->desc.wMaxPacketSize;
+
+       rpipe->descr.hwa_bMaxBurst = max(min_t(unsigned int,
+                               epcd->bMaxBurst, 16U), 1U);
+       rpipe->descr.hwa_bDeviceInfoIndex =
+                       wusb_port_no_to_idx(urb->dev->portnum);
+       /* FIXME: use maximum speed as supported or recommended by device */
+       rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ?
+               UWB_PHY_RATE_53 : UWB_PHY_RATE_200;
+
+       dev_dbg(dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n",
+               urb->dev->devnum, urb->dev->devnum | unauth,
+               le16_to_cpu(rpipe->descr.wRPipeIndex),
+               usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed);
+
+       rpipe->descr.hwa_reserved = 0;
+
+       rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress;
+       /* FIXME: bDataSequence */
+       rpipe->descr.bDataSequence = 0;
+
+       /* start with base window of hwa_bMaxBurst bits starting at 0. */
+       ack_window = 0xFFFFFFFF >> (32 - rpipe->descr.hwa_bMaxBurst);
+       rpipe->descr.dwCurrentWindow = cpu_to_le32(ack_window);
+       epcd_max_sequence = max(min_t(unsigned int,
+                       epcd->bMaxSequence, 32U), 2U);
+       rpipe->descr.bMaxDataSequence = epcd_max_sequence - 1;
+       rpipe->descr.bInterval = ep->desc.bInterval;
+       if (usb_endpoint_xfer_isoc(&ep->desc))
+               rpipe->descr.bOverTheAirInterval = epcd->bOverTheAirInterval;
+       else
+               rpipe->descr.bOverTheAirInterval = 0;   /* 0 if not isoc */
+       /* FIXME: xmit power & preamble blah blah */
+       rpipe->descr.bmAttribute = (ep->desc.bmAttributes &
+                                       USB_ENDPOINT_XFERTYPE_MASK);
+       /* rpipe->descr.bmCharacteristics RO */
+       rpipe->descr.bmRetryOptions = (wa->wusb->retry_count & 0xF);
+       /* FIXME: use for assessing link quality? */
+       rpipe->descr.wNumTransactionErrors = 0;
+       result = __rpipe_set_descr(wa, &rpipe->descr,
+                                  le16_to_cpu(rpipe->descr.wRPipeIndex));
+       if (result < 0) {
+               dev_err(dev, "Cannot aim rpipe: %d\n", result);
+               goto error;
+       }
+       result = 0;
+error:
+       return result;
+}
+
+/*
+ * Check an aimed rpipe to make sure it points to where we want
+ *
+ * We use bit 19 of the Linux USB pipe bitmap for unauth vs auth
+ * space; when it is like that, we or 0x80 to make an unauth address.
+ */
+static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa,
+                          const struct usb_host_endpoint *ep,
+                          const struct urb *urb, gfp_t gfp)
+{
+       int result = 0;
+       struct device *dev = &wa->usb_iface->dev;
+       u8 portnum = wusb_port_no_to_idx(urb->dev->portnum);
+
+#define AIM_CHECK(rdf, val, text)                                      \
+       do {                                                            \
+               if (rpipe->descr.rdf != (val)) {                        \
+                       dev_err(dev,                                    \
+                               "rpipe aim discrepancy: " #rdf " " text "\n", \
+                               rpipe->descr.rdf, (val));               \
+                       result = -EINVAL;                               \
+                       WARN_ON(1);                                     \
+               }                                                       \
+       } while (0)
+       AIM_CHECK(hwa_bDeviceInfoIndex, portnum, "(%u vs %u)");
+       AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ?
+                       UWB_PHY_RATE_53 : UWB_PHY_RATE_200,
+                 "(%u vs %u)");
+       AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)");
+       AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)");
+       AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)");
+#undef AIM_CHECK
+       return result;
+}
+
+#ifndef CONFIG_BUG
+#define CONFIG_BUG 0
+#endif
+
+/*
+ * Make sure there is an rpipe allocated for an endpoint
+ *
+ * If already allocated, we just refcount it; if not, we get an
+ * idle one, aim it to the right location and take it.
+ *
+ * Attaches to ep->hcpriv and rpipe->ep to ep.
+ */
+int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep,
+                   struct urb *urb, gfp_t gfp)
+{
+       int result = 0;
+       struct device *dev = &wa->usb_iface->dev;
+       struct wa_rpipe *rpipe;
+       u8 eptype;
+
+       mutex_lock(&wa->rpipe_mutex);
+       rpipe = ep->hcpriv;
+       if (rpipe != NULL) {
+               if (CONFIG_BUG == 1) {
+                       result = rpipe_check_aim(rpipe, wa, ep, urb, gfp);
+                       if (result < 0)
+                               goto error;
+               }
+               __rpipe_get(rpipe);
+               dev_dbg(dev, "ep 0x%02x: reusing rpipe %u\n",
+                       ep->desc.bEndpointAddress,
+                       le16_to_cpu(rpipe->descr.wRPipeIndex));
+       } else {
+               /* hmm, assign idle rpipe, aim it */
+               result = -ENOBUFS;
+               eptype = ep->desc.bmAttributes & 0x03;
+               result = rpipe_get_idle(&rpipe, wa, 1 << eptype, gfp);
+               if (result < 0)
+                       goto error;
+               result = rpipe_aim(rpipe, wa, ep, urb, gfp);
+               if (result < 0) {
+                       rpipe_put(rpipe);
+                       goto error;
+               }
+               ep->hcpriv = rpipe;
+               rpipe->ep = ep;
+               __rpipe_get(rpipe);     /* for caching into ep->hcpriv */
+               dev_dbg(dev, "ep 0x%02x: using rpipe %u\n",
+                       ep->desc.bEndpointAddress,
+                       le16_to_cpu(rpipe->descr.wRPipeIndex));
+       }
+error:
+       mutex_unlock(&wa->rpipe_mutex);
+       return result;
+}
+
+/*
+ * Allocate the bitmap for each rpipe.
+ */
+int wa_rpipes_create(struct wahc *wa)
+{
+       wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes);
+       wa->rpipe_bm = bitmap_zalloc(wa->rpipes, GFP_KERNEL);
+       if (wa->rpipe_bm == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+void wa_rpipes_destroy(struct wahc *wa)
+{
+       struct device *dev = &wa->usb_iface->dev;
+
+       if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) {
+               WARN_ON(1);
+               dev_err(dev, "BUG: pipes not released on exit: %*pb\n",
+                       wa->rpipes, wa->rpipe_bm);
+       }
+       bitmap_free(wa->rpipe_bm);
+}
+
+/*
+ * Release resources allocated for an endpoint
+ *
+ * If there is an associated rpipe to this endpoint, Abort any pending
+ * transfers and put it. If the rpipe ends up being destroyed,
+ * __rpipe_destroy() will cleanup ep->hcpriv.
+ *
+ * This is called before calling hcd->stop(), so you don't need to do
+ * anything else in there.
+ */
+void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep)
+{
+       struct wa_rpipe *rpipe;
+
+       mutex_lock(&wa->rpipe_mutex);
+       rpipe = ep->hcpriv;
+       if (rpipe != NULL) {
+               u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+
+               usb_control_msg(
+                       wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       USB_REQ_RPIPE_ABORT,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+                       0, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
+               rpipe_put(rpipe);
+       }
+       mutex_unlock(&wa->rpipe_mutex);
+}
+EXPORT_SYMBOL_GPL(rpipe_ep_disable);
+
+/* Clear the stalled status of an RPIPE. */
+void rpipe_clear_feature_stalled(struct wahc *wa, struct usb_host_endpoint *ep)
+{
+       struct wa_rpipe *rpipe;
+
+       mutex_lock(&wa->rpipe_mutex);
+       rpipe = ep->hcpriv;
+       if (rpipe != NULL) {
+               u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
+
+               usb_control_msg(
+                       wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
+                       USB_REQ_CLEAR_FEATURE,
+                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
+                       RPIPE_STALL, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
+       }
+       mutex_unlock(&wa->rpipe_mutex);
+}
+EXPORT_SYMBOL_GPL(rpipe_clear_feature_stalled);
diff --git a/drivers/staging/wusbcore/wa-xfer.c b/drivers/staging/wusbcore/wa-xfer.c
new file mode 100644 (file)
index 0000000..abf88ce
--- /dev/null
@@ -0,0 +1,2927 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * WUSB Wire Adapter
+ * Data transfer and URB enqueing
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * How transfers work: get a buffer, break it up in segments (segment
+ * size is a multiple of the maxpacket size). For each segment issue a
+ * segment request (struct wa_xfer_*), then send the data buffer if
+ * out or nothing if in (all over the DTO endpoint).
+ *
+ * For each submitted segment request, a notification will come over
+ * the NEP endpoint and a transfer result (struct xfer_result) will
+ * arrive in the DTI URB. Read it, get the xfer ID, see if there is
+ * data coming (inbound transfer), schedule a read and handle it.
+ *
+ * Sounds simple, it is a pain to implement.
+ *
+ *
+ * ENTRY POINTS
+ *
+ *   FIXME
+ *
+ * LIFE CYCLE / STATE DIAGRAM
+ *
+ *   FIXME
+ *
+ * THIS CODE IS DISGUSTING
+ *
+ *   Warned you are; it's my second try and still not happy with it.
+ *
+ * NOTES:
+ *
+ *   - No iso
+ *
+ *   - Supports DMA xfers, control, bulk and maybe interrupt
+ *
+ *   - Does not recycle unused rpipes
+ *
+ *     An rpipe is assigned to an endpoint the first time it is used,
+ *     and then it's there, assigned, until the endpoint is disabled
+ *     (destroyed [{h,d}wahc_op_ep_disable()]. The assignment of the
+ *     rpipe to the endpoint is done under the wa->rpipe_sem semaphore
+ *     (should be a mutex).
+ *
+ *     Two methods it could be done:
+ *
+ *     (a) set up a timer every time an rpipe's use count drops to 1
+ *         (which means unused) or when a transfer ends. Reset the
+ *         timer when a xfer is queued. If the timer expires, release
+ *         the rpipe [see rpipe_ep_disable()].
+ *
+ *     (b) when looking for free rpipes to attach [rpipe_get_by_ep()],
+ *         when none are found go over the list, check their endpoint
+ *         and their activity record (if no last-xfer-done-ts in the
+ *         last x seconds) take it
+ *
+ *     However, due to the fact that we have a set of limited
+ *     resources (max-segments-at-the-same-time per xfer,
+ *     xfers-per-ripe, blocks-per-rpipe, rpipes-per-host), at the end
+ *     we are going to have to rebuild all this based on an scheduler,
+ *     to where we have a list of transactions to do and based on the
+ *     availability of the different required components (blocks,
+ *     rpipes, segment slots, etc), we go scheduling them. Painful.
+ */
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/hash.h>
+#include <linux/ratelimit.h>
+#include <linux/export.h>
+#include <linux/scatterlist.h>
+
+#include "wa-hc.h"
+#include "wusbhc.h"
+
+enum {
+       /* [WUSB] section 8.3.3 allocates 7 bits for the segment index. */
+       WA_SEGS_MAX = 128,
+};
+
+enum wa_seg_status {
+       WA_SEG_NOTREADY,
+       WA_SEG_READY,
+       WA_SEG_DELAYED,
+       WA_SEG_SUBMITTED,
+       WA_SEG_PENDING,
+       WA_SEG_DTI_PENDING,
+       WA_SEG_DONE,
+       WA_SEG_ERROR,
+       WA_SEG_ABORTED,
+};
+
+static void wa_xfer_delayed_run(struct wa_rpipe *);
+static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting);
+
+/*
+ * Life cycle governed by 'struct urb' (the refcount of the struct is
+ * that of the 'struct urb' and usb_free_urb() would free the whole
+ * struct).
+ */
+struct wa_seg {
+       struct urb tr_urb;              /* transfer request urb. */
+       struct urb *isoc_pack_desc_urb; /* for isoc packet descriptor. */
+       struct urb *dto_urb;            /* for data output. */
+       struct list_head list_node;     /* for rpipe->req_list */
+       struct wa_xfer *xfer;           /* out xfer */
+       u8 index;                       /* which segment we are */
+       int isoc_frame_count;   /* number of isoc frames in this segment. */
+       int isoc_frame_offset;  /* starting frame offset in the xfer URB. */
+       /* Isoc frame that the current transfer buffer corresponds to. */
+       int isoc_frame_index;
+       int isoc_size;  /* size of all isoc frames sent by this seg. */
+       enum wa_seg_status status;
+       ssize_t result;                 /* bytes xfered or error */
+       struct wa_xfer_hdr xfer_hdr;
+};
+
+static inline void wa_seg_init(struct wa_seg *seg)
+{
+       usb_init_urb(&seg->tr_urb);
+
+       /* set the remaining memory to 0. */
+       memset(((void *)seg) + sizeof(seg->tr_urb), 0,
+               sizeof(*seg) - sizeof(seg->tr_urb));
+}
+
+/*
+ * Protected by xfer->lock
+ *
+ */
+struct wa_xfer {
+       struct kref refcnt;
+       struct list_head list_node;
+       spinlock_t lock;
+       u32 id;
+
+       struct wahc *wa;                /* Wire adapter we are plugged to */
+       struct usb_host_endpoint *ep;
+       struct urb *urb;                /* URB we are transferring for */
+       struct wa_seg **seg;            /* transfer segments */
+       u8 segs, segs_submitted, segs_done;
+       unsigned is_inbound:1;
+       unsigned is_dma:1;
+       size_t seg_size;
+       int result;
+
+       gfp_t gfp;                      /* allocation mask */
+
+       struct wusb_dev *wusb_dev;      /* for activity timestamps */
+};
+
+static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer,
+       struct wa_seg *seg, int curr_iso_frame);
+static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
+               int starting_index, enum wa_seg_status status);
+
+static inline void wa_xfer_init(struct wa_xfer *xfer)
+{
+       kref_init(&xfer->refcnt);
+       INIT_LIST_HEAD(&xfer->list_node);
+       spin_lock_init(&xfer->lock);
+}
+
+/*
+ * Destroy a transfer structure
+ *
+ * Note that freeing xfer->seg[cnt]->tr_urb will free the containing
+ * xfer->seg[cnt] memory that was allocated by __wa_xfer_setup_segs.
+ */
+static void wa_xfer_destroy(struct kref *_xfer)
+{
+       struct wa_xfer *xfer = container_of(_xfer, struct wa_xfer, refcnt);
+       if (xfer->seg) {
+               unsigned cnt;
+               for (cnt = 0; cnt < xfer->segs; cnt++) {
+                       struct wa_seg *seg = xfer->seg[cnt];
+                       if (seg) {
+                               usb_free_urb(seg->isoc_pack_desc_urb);
+                               if (seg->dto_urb) {
+                                       kfree(seg->dto_urb->sg);
+                                       usb_free_urb(seg->dto_urb);
+                               }
+                               usb_free_urb(&seg->tr_urb);
+                       }
+               }
+               kfree(xfer->seg);
+       }
+       kfree(xfer);
+}
+
+static void wa_xfer_get(struct wa_xfer *xfer)
+{
+       kref_get(&xfer->refcnt);
+}
+
+static void wa_xfer_put(struct wa_xfer *xfer)
+{
+       kref_put(&xfer->refcnt, wa_xfer_destroy);
+}
+
+/*
+ * Try to get exclusive access to the DTO endpoint resource.  Return true
+ * if successful.
+ */
+static inline int __wa_dto_try_get(struct wahc *wa)
+{
+       return (test_and_set_bit(0, &wa->dto_in_use) == 0);
+}
+
+/* Release the DTO endpoint resource. */
+static inline void __wa_dto_put(struct wahc *wa)
+{
+       clear_bit_unlock(0, &wa->dto_in_use);
+}
+
+/* Service RPIPEs that are waiting on the DTO resource. */
+static void wa_check_for_delayed_rpipes(struct wahc *wa)
+{
+       unsigned long flags;
+       int dto_waiting = 0;
+       struct wa_rpipe *rpipe;
+
+       spin_lock_irqsave(&wa->rpipe_lock, flags);
+       while (!list_empty(&wa->rpipe_delayed_list) && !dto_waiting) {
+               rpipe = list_first_entry(&wa->rpipe_delayed_list,
+                               struct wa_rpipe, list_node);
+               __wa_xfer_delayed_run(rpipe, &dto_waiting);
+               /* remove this RPIPE from the list if it is not waiting. */
+               if (!dto_waiting) {
+                       pr_debug("%s: RPIPE %d serviced and removed from delayed list.\n",
+                               __func__,
+                               le16_to_cpu(rpipe->descr.wRPipeIndex));
+                       list_del_init(&rpipe->list_node);
+               }
+       }
+       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
+}
+
+/* add this RPIPE to the end of the delayed RPIPE list. */
+static void wa_add_delayed_rpipe(struct wahc *wa, struct wa_rpipe *rpipe)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&wa->rpipe_lock, flags);
+       /* add rpipe to the list if it is not already on it. */
+       if (list_empty(&rpipe->list_node)) {
+               pr_debug("%s: adding RPIPE %d to the delayed list.\n",
+                       __func__, le16_to_cpu(rpipe->descr.wRPipeIndex));
+               list_add_tail(&rpipe->list_node, &wa->rpipe_delayed_list);
+       }
+       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
+}
+
+/*
+ * xfer is referenced
+ *
+ * xfer->lock has to be unlocked
+ *
+ * We take xfer->lock for setting the result; this is a barrier
+ * against drivers/usb/core/hcd.c:unlink1() being called after we call
+ * usb_hcd_giveback_urb() and wa_urb_dequeue() trying to get a
+ * reference to the transfer.
+ */
+static void wa_xfer_giveback(struct wa_xfer *xfer)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&xfer->wa->xfer_list_lock, flags);
+       list_del_init(&xfer->list_node);
+       usb_hcd_unlink_urb_from_ep(&(xfer->wa->wusb->usb_hcd), xfer->urb);
+       spin_unlock_irqrestore(&xfer->wa->xfer_list_lock, flags);
+       /* FIXME: segmentation broken -- kills DWA */
+       wusbhc_giveback_urb(xfer->wa->wusb, xfer->urb, xfer->result);
+       wa_put(xfer->wa);
+       wa_xfer_put(xfer);
+}
+
+/*
+ * xfer is referenced
+ *
+ * xfer->lock has to be unlocked
+ */
+static void wa_xfer_completion(struct wa_xfer *xfer)
+{
+       if (xfer->wusb_dev)
+               wusb_dev_put(xfer->wusb_dev);
+       rpipe_put(xfer->ep->hcpriv);
+       wa_xfer_giveback(xfer);
+}
+
+/*
+ * Initialize a transfer's ID
+ *
+ * We need to use a sequential number; if we use the pointer or the
+ * hash of the pointer, it can repeat over sequential transfers and
+ * then it will confuse the HWA....wonder why in hell they put a 32
+ * bit handle in there then.
+ */
+static void wa_xfer_id_init(struct wa_xfer *xfer)
+{
+       xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count);
+}
+
+/* Return the xfer's ID. */
+static inline u32 wa_xfer_id(struct wa_xfer *xfer)
+{
+       return xfer->id;
+}
+
+/* Return the xfer's ID in transport format (little endian). */
+static inline __le32 wa_xfer_id_le32(struct wa_xfer *xfer)
+{
+       return cpu_to_le32(xfer->id);
+}
+
+/*
+ * If transfer is done, wrap it up and return true
+ *
+ * xfer->lock has to be locked
+ */
+static unsigned __wa_xfer_is_done(struct wa_xfer *xfer)
+{
+       struct device *dev = &xfer->wa->usb_iface->dev;
+       unsigned result, cnt;
+       struct wa_seg *seg;
+       struct urb *urb = xfer->urb;
+       unsigned found_short = 0;
+
+       result = xfer->segs_done == xfer->segs_submitted;
+       if (result == 0)
+               goto out;
+       urb->actual_length = 0;
+       for (cnt = 0; cnt < xfer->segs; cnt++) {
+               seg = xfer->seg[cnt];
+               switch (seg->status) {
+               case WA_SEG_DONE:
+                       if (found_short && seg->result > 0) {
+                               dev_dbg(dev, "xfer %p ID %08X#%u: bad short segments (%zu)\n",
+                                       xfer, wa_xfer_id(xfer), cnt,
+                                       seg->result);
+                               urb->status = -EINVAL;
+                               goto out;
+                       }
+                       urb->actual_length += seg->result;
+                       if (!(usb_pipeisoc(xfer->urb->pipe))
+                               && seg->result < xfer->seg_size
+                           && cnt != xfer->segs-1)
+                               found_short = 1;
+                       dev_dbg(dev, "xfer %p ID %08X#%u: DONE short %d "
+                               "result %zu urb->actual_length %d\n",
+                               xfer, wa_xfer_id(xfer), seg->index, found_short,
+                               seg->result, urb->actual_length);
+                       break;
+               case WA_SEG_ERROR:
+                       xfer->result = seg->result;
+                       dev_dbg(dev, "xfer %p ID %08X#%u: ERROR result %zi(0x%08zX)\n",
+                               xfer, wa_xfer_id(xfer), seg->index, seg->result,
+                               seg->result);
+                       goto out;
+               case WA_SEG_ABORTED:
+                       xfer->result = seg->result;
+                       dev_dbg(dev, "xfer %p ID %08X#%u: ABORTED result %zi(0x%08zX)\n",
+                               xfer, wa_xfer_id(xfer), seg->index, seg->result,
+                               seg->result);
+                       goto out;
+               default:
+                       dev_warn(dev, "xfer %p ID %08X#%u: is_done bad state %d\n",
+                                xfer, wa_xfer_id(xfer), cnt, seg->status);
+                       xfer->result = -EINVAL;
+                       goto out;
+               }
+       }
+       xfer->result = 0;
+out:
+       return result;
+}
+
+/*
+ * Mark the given segment as done.  Return true if this completes the xfer.
+ * This should only be called for segs that have been submitted to an RPIPE.
+ * Delayed segs are not marked as submitted so they do not need to be marked
+ * as done when cleaning up.
+ *
+ * xfer->lock has to be locked
+ */
+static unsigned __wa_xfer_mark_seg_as_done(struct wa_xfer *xfer,
+       struct wa_seg *seg, enum wa_seg_status status)
+{
+       seg->status = status;
+       xfer->segs_done++;
+
+       /* check for done. */
+       return __wa_xfer_is_done(xfer);
+}
+
+/*
+ * Search for a transfer list ID on the HCD's URB list
+ *
+ * For 32 bit architectures, we use the pointer itself; for 64 bits, a
+ * 32-bit hash of the pointer.
+ *
+ * @returns NULL if not found.
+ */
+static struct wa_xfer *wa_xfer_get_by_id(struct wahc *wa, u32 id)
+{
+       unsigned long flags;
+       struct wa_xfer *xfer_itr;
+       spin_lock_irqsave(&wa->xfer_list_lock, flags);
+       list_for_each_entry(xfer_itr, &wa->xfer_list, list_node) {
+               if (id == xfer_itr->id) {
+                       wa_xfer_get(xfer_itr);
+                       goto out;
+               }
+       }
+       xfer_itr = NULL;
+out:
+       spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
+       return xfer_itr;
+}
+
+struct wa_xfer_abort_buffer {
+       struct urb urb;
+       struct wahc *wa;
+       struct wa_xfer_abort cmd;
+};
+
+static void __wa_xfer_abort_cb(struct urb *urb)
+{
+       struct wa_xfer_abort_buffer *b = urb->context;
+       struct wahc *wa = b->wa;
+
+       /*
+        * If the abort request URB failed, then the HWA did not get the abort
+        * command.  Forcibly clean up the xfer without waiting for a Transfer
+        * Result from the HWA.
+        */
+       if (urb->status < 0) {
+               struct wa_xfer *xfer;
+               struct device *dev = &wa->usb_iface->dev;
+
+               xfer = wa_xfer_get_by_id(wa, le32_to_cpu(b->cmd.dwTransferID));
+               dev_err(dev, "%s: Transfer Abort request failed. result: %d\n",
+                       __func__, urb->status);
+               if (xfer) {
+                       unsigned long flags;
+                       int done, seg_index = 0;
+                       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+                       dev_err(dev, "%s: cleaning up xfer %p ID 0x%08X.\n",
+                               __func__, xfer, wa_xfer_id(xfer));
+                       spin_lock_irqsave(&xfer->lock, flags);
+                       /* skip done segs. */
+                       while (seg_index < xfer->segs) {
+                               struct wa_seg *seg = xfer->seg[seg_index];
+
+                               if ((seg->status == WA_SEG_DONE) ||
+                                       (seg->status == WA_SEG_ERROR)) {
+                                       ++seg_index;
+                               } else {
+                                       break;
+                               }
+                       }
+                       /* mark remaining segs as aborted. */
+                       wa_complete_remaining_xfer_segs(xfer, seg_index,
+                               WA_SEG_ABORTED);
+                       done = __wa_xfer_is_done(xfer);
+                       spin_unlock_irqrestore(&xfer->lock, flags);
+                       if (done)
+                               wa_xfer_completion(xfer);
+                       wa_xfer_delayed_run(rpipe);
+                       wa_xfer_put(xfer);
+               } else {
+                       dev_err(dev, "%s: xfer ID 0x%08X already gone.\n",
+                                __func__, le32_to_cpu(b->cmd.dwTransferID));
+               }
+       }
+
+       wa_put(wa);     /* taken in __wa_xfer_abort */
+       usb_put_urb(&b->urb);
+}
+
+/*
+ * Aborts an ongoing transaction
+ *
+ * Assumes the transfer is referenced and locked and in a submitted
+ * state (mainly that there is an endpoint/rpipe assigned).
+ *
+ * The callback (see above) does nothing but freeing up the data by
+ * putting the URB. Because the URB is allocated at the head of the
+ * struct, the whole space we allocated is kfreed. *
+ */
+static int __wa_xfer_abort(struct wa_xfer *xfer)
+{
+       int result = -ENOMEM;
+       struct device *dev = &xfer->wa->usb_iface->dev;
+       struct wa_xfer_abort_buffer *b;
+       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+       b = kmalloc(sizeof(*b), GFP_ATOMIC);
+       if (b == NULL)
+               goto error_kmalloc;
+       b->cmd.bLength =  sizeof(b->cmd);
+       b->cmd.bRequestType = WA_XFER_ABORT;
+       b->cmd.wRPipe = rpipe->descr.wRPipeIndex;
+       b->cmd.dwTransferID = wa_xfer_id_le32(xfer);
+       b->wa = wa_get(xfer->wa);
+
+       usb_init_urb(&b->urb);
+       usb_fill_bulk_urb(&b->urb, xfer->wa->usb_dev,
+               usb_sndbulkpipe(xfer->wa->usb_dev,
+                               xfer->wa->dto_epd->bEndpointAddress),
+               &b->cmd, sizeof(b->cmd), __wa_xfer_abort_cb, b);
+       result = usb_submit_urb(&b->urb, GFP_ATOMIC);
+       if (result < 0)
+               goto error_submit;
+       return result;                          /* callback frees! */
+
+
+error_submit:
+       wa_put(xfer->wa);
+       if (printk_ratelimit())
+               dev_err(dev, "xfer %p: Can't submit abort request: %d\n",
+                       xfer, result);
+       kfree(b);
+error_kmalloc:
+       return result;
+
+}
+
+/*
+ * Calculate the number of isoc frames starting from isoc_frame_offset
+ * that will fit a in transfer segment.
+ */
+static int __wa_seg_calculate_isoc_frame_count(struct wa_xfer *xfer,
+       int isoc_frame_offset, int *total_size)
+{
+       int segment_size = 0, frame_count = 0;
+       int index = isoc_frame_offset;
+       struct usb_iso_packet_descriptor *iso_frame_desc =
+               xfer->urb->iso_frame_desc;
+
+       while ((index < xfer->urb->number_of_packets)
+               && ((segment_size + iso_frame_desc[index].length)
+                               <= xfer->seg_size)) {
+               /*
+                * For Alereon HWA devices, only include an isoc frame in an
+                * out segment if it is physically contiguous with the previous
+                * frame.  This is required because those devices expect
+                * the isoc frames to be sent as a single USB transaction as
+                * opposed to one transaction per frame with standard HWA.
+                */
+               if ((xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
+                       && (xfer->is_inbound == 0)
+                       && (index > isoc_frame_offset)
+                       && ((iso_frame_desc[index - 1].offset +
+                               iso_frame_desc[index - 1].length) !=
+                               iso_frame_desc[index].offset))
+                       break;
+
+               /* this frame fits. count it. */
+               ++frame_count;
+               segment_size += iso_frame_desc[index].length;
+
+               /* move to the next isoc frame. */
+               ++index;
+       }
+
+       *total_size = segment_size;
+       return frame_count;
+}
+
+/*
+ *
+ * @returns < 0 on error, transfer segment request size if ok
+ */
+static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer,
+                                    enum wa_xfer_type *pxfer_type)
+{
+       ssize_t result;
+       struct device *dev = &xfer->wa->usb_iface->dev;
+       size_t maxpktsize;
+       struct urb *urb = xfer->urb;
+       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+       switch (rpipe->descr.bmAttribute & 0x3) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               *pxfer_type = WA_XFER_TYPE_CTL;
+               result = sizeof(struct wa_xfer_ctl);
+               break;
+       case USB_ENDPOINT_XFER_INT:
+       case USB_ENDPOINT_XFER_BULK:
+               *pxfer_type = WA_XFER_TYPE_BI;
+               result = sizeof(struct wa_xfer_bi);
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               *pxfer_type = WA_XFER_TYPE_ISO;
+               result = sizeof(struct wa_xfer_hwaiso);
+               break;
+       default:
+               /* never happens */
+               BUG();
+               result = -EINVAL;       /* shut gcc up */
+       }
+       xfer->is_inbound = urb->pipe & USB_DIR_IN ? 1 : 0;
+       xfer->is_dma = urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? 1 : 0;
+
+       maxpktsize = le16_to_cpu(rpipe->descr.wMaxPacketSize);
+       xfer->seg_size = le16_to_cpu(rpipe->descr.wBlocks)
+               * 1 << (xfer->wa->wa_descr->bRPipeBlockSize - 1);
+       /* Compute the segment size and make sure it is a multiple of
+        * the maxpktsize (WUSB1.0[8.3.3.1])...not really too much of
+        * a check (FIXME) */
+       if (xfer->seg_size < maxpktsize) {
+               dev_err(dev,
+                       "HW BUG? seg_size %zu smaller than maxpktsize %zu\n",
+                       xfer->seg_size, maxpktsize);
+               result = -EINVAL;
+               goto error;
+       }
+       xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize;
+       if ((rpipe->descr.bmAttribute & 0x3) == USB_ENDPOINT_XFER_ISOC) {
+               int index = 0;
+
+               xfer->segs = 0;
+               /*
+                * loop over urb->number_of_packets to determine how many
+                * xfer segments will be needed to send the isoc frames.
+                */
+               while (index < urb->number_of_packets) {
+                       int seg_size; /* don't care. */
+                       index += __wa_seg_calculate_isoc_frame_count(xfer,
+                                       index, &seg_size);
+                       ++xfer->segs;
+               }
+       } else {
+               xfer->segs = DIV_ROUND_UP(urb->transfer_buffer_length,
+                                               xfer->seg_size);
+               if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL)
+                       xfer->segs = 1;
+       }
+
+       if (xfer->segs > WA_SEGS_MAX) {
+               dev_err(dev, "BUG? oops, number of segments %zu bigger than %d\n",
+                       (urb->transfer_buffer_length/xfer->seg_size),
+                       WA_SEGS_MAX);
+               result = -EINVAL;
+               goto error;
+       }
+error:
+       return result;
+}
+
+static void __wa_setup_isoc_packet_descr(
+               struct wa_xfer_packet_info_hwaiso *packet_desc,
+               struct wa_xfer *xfer,
+               struct wa_seg *seg) {
+       struct usb_iso_packet_descriptor *iso_frame_desc =
+               xfer->urb->iso_frame_desc;
+       int frame_index;
+
+       /* populate isoc packet descriptor. */
+       packet_desc->bPacketType = WA_XFER_ISO_PACKET_INFO;
+       packet_desc->wLength = cpu_to_le16(struct_size(packet_desc,
+                                          PacketLength,
+                                          seg->isoc_frame_count));
+       for (frame_index = 0; frame_index < seg->isoc_frame_count;
+               ++frame_index) {
+               int offset_index = frame_index + seg->isoc_frame_offset;
+               packet_desc->PacketLength[frame_index] =
+                       cpu_to_le16(iso_frame_desc[offset_index].length);
+       }
+}
+
+
+/* Fill in the common request header and xfer-type specific data. */
+static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer,
+                                struct wa_xfer_hdr *xfer_hdr0,
+                                enum wa_xfer_type xfer_type,
+                                size_t xfer_hdr_size)
+{
+       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+       struct wa_seg *seg = xfer->seg[0];
+
+       xfer_hdr0 = &seg->xfer_hdr;
+       xfer_hdr0->bLength = xfer_hdr_size;
+       xfer_hdr0->bRequestType = xfer_type;
+       xfer_hdr0->wRPipe = rpipe->descr.wRPipeIndex;
+       xfer_hdr0->dwTransferID = wa_xfer_id_le32(xfer);
+       xfer_hdr0->bTransferSegment = 0;
+       switch (xfer_type) {
+       case WA_XFER_TYPE_CTL: {
+               struct wa_xfer_ctl *xfer_ctl =
+                       container_of(xfer_hdr0, struct wa_xfer_ctl, hdr);
+               xfer_ctl->bmAttribute = xfer->is_inbound ? 1 : 0;
+               memcpy(&xfer_ctl->baSetupData, xfer->urb->setup_packet,
+                      sizeof(xfer_ctl->baSetupData));
+               break;
+       }
+       case WA_XFER_TYPE_BI:
+               break;
+       case WA_XFER_TYPE_ISO: {
+               struct wa_xfer_hwaiso *xfer_iso =
+                       container_of(xfer_hdr0, struct wa_xfer_hwaiso, hdr);
+               struct wa_xfer_packet_info_hwaiso *packet_desc =
+                       ((void *)xfer_iso) + xfer_hdr_size;
+
+               /* populate the isoc section of the transfer request. */
+               xfer_iso->dwNumOfPackets = cpu_to_le32(seg->isoc_frame_count);
+               /* populate isoc packet descriptor. */
+               __wa_setup_isoc_packet_descr(packet_desc, xfer, seg);
+               break;
+       }
+       default:
+               BUG();
+       };
+}
+
+/*
+ * Callback for the OUT data phase of the segment request
+ *
+ * Check wa_seg_tr_cb(); most comments also apply here because this
+ * function does almost the same thing and they work closely
+ * together.
+ *
+ * If the seg request has failed but this DTO phase has succeeded,
+ * wa_seg_tr_cb() has already failed the segment and moved the
+ * status to WA_SEG_ERROR, so this will go through 'case 0' and
+ * effectively do nothing.
+ */
+static void wa_seg_dto_cb(struct urb *urb)
+{
+       struct wa_seg *seg = urb->context;
+       struct wa_xfer *xfer = seg->xfer;
+       struct wahc *wa;
+       struct device *dev;
+       struct wa_rpipe *rpipe;
+       unsigned long flags;
+       unsigned rpipe_ready = 0;
+       int data_send_done = 1, release_dto = 0, holding_dto = 0;
+       u8 done = 0;
+       int result;
+
+       /* free the sg if it was used. */
+       kfree(urb->sg);
+       urb->sg = NULL;
+
+       spin_lock_irqsave(&xfer->lock, flags);
+       wa = xfer->wa;
+       dev = &wa->usb_iface->dev;
+       if (usb_pipeisoc(xfer->urb->pipe)) {
+               /* Alereon HWA sends all isoc frames in a single transfer. */
+               if (wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
+                       seg->isoc_frame_index += seg->isoc_frame_count;
+               else
+                       seg->isoc_frame_index += 1;
+               if (seg->isoc_frame_index < seg->isoc_frame_count) {
+                       data_send_done = 0;
+                       holding_dto = 1; /* checked in error cases. */
+                       /*
+                        * if this is the last isoc frame of the segment, we
+                        * can release DTO after sending this frame.
+                        */
+                       if ((seg->isoc_frame_index + 1) >=
+                               seg->isoc_frame_count)
+                               release_dto = 1;
+               }
+               dev_dbg(dev, "xfer 0x%08X#%u: isoc frame = %d, holding_dto = %d, release_dto = %d.\n",
+                       wa_xfer_id(xfer), seg->index, seg->isoc_frame_index,
+                       holding_dto, release_dto);
+       }
+       spin_unlock_irqrestore(&xfer->lock, flags);
+
+       switch (urb->status) {
+       case 0:
+               spin_lock_irqsave(&xfer->lock, flags);
+               seg->result += urb->actual_length;
+               if (data_send_done) {
+                       dev_dbg(dev, "xfer 0x%08X#%u: data out done (%zu bytes)\n",
+                               wa_xfer_id(xfer), seg->index, seg->result);
+                       if (seg->status < WA_SEG_PENDING)
+                               seg->status = WA_SEG_PENDING;
+               } else {
+                       /* should only hit this for isoc xfers. */
+                       /*
+                        * Populate the dto URB with the next isoc frame buffer,
+                        * send the URB and release DTO if we no longer need it.
+                        */
+                        __wa_populate_dto_urb_isoc(xfer, seg,
+                               seg->isoc_frame_offset + seg->isoc_frame_index);
+
+                       /* resubmit the URB with the next isoc frame. */
+                       /* take a ref on resubmit. */
+                       wa_xfer_get(xfer);
+                       result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
+                       if (result < 0) {
+                               dev_err(dev, "xfer 0x%08X#%u: DTO submit failed: %d\n",
+                                      wa_xfer_id(xfer), seg->index, result);
+                               spin_unlock_irqrestore(&xfer->lock, flags);
+                               goto error_dto_submit;
+                       }
+               }
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               if (release_dto) {
+                       __wa_dto_put(wa);
+                       wa_check_for_delayed_rpipes(wa);
+               }
+               break;
+       case -ECONNRESET:       /* URB unlinked; no need to do anything */
+       case -ENOENT:           /* as it was done by the who unlinked us */
+               if (holding_dto) {
+                       __wa_dto_put(wa);
+                       wa_check_for_delayed_rpipes(wa);
+               }
+               break;
+       default:                /* Other errors ... */
+               dev_err(dev, "xfer 0x%08X#%u: data out error %d\n",
+                       wa_xfer_id(xfer), seg->index, urb->status);
+               goto error_default;
+       }
+
+       /* taken when this URB was submitted. */
+       wa_xfer_put(xfer);
+       return;
+
+error_dto_submit:
+       /* taken on resubmit attempt. */
+       wa_xfer_put(xfer);
+error_default:
+       spin_lock_irqsave(&xfer->lock, flags);
+       rpipe = xfer->ep->hcpriv;
+       if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+                   EDC_ERROR_TIMEFRAME)){
+               dev_err(dev, "DTO: URB max acceptable errors exceeded, resetting device\n");
+               wa_reset_all(wa);
+       }
+       if (seg->status != WA_SEG_ERROR) {
+               seg->result = urb->status;
+               __wa_xfer_abort(xfer);
+               rpipe_ready = rpipe_avail_inc(rpipe);
+               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);
+       }
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       if (holding_dto) {
+               __wa_dto_put(wa);
+               wa_check_for_delayed_rpipes(wa);
+       }
+       if (done)
+               wa_xfer_completion(xfer);
+       if (rpipe_ready)
+               wa_xfer_delayed_run(rpipe);
+       /* taken when this URB was submitted. */
+       wa_xfer_put(xfer);
+}
+
+/*
+ * Callback for the isoc packet descriptor phase of the segment request
+ *
+ * Check wa_seg_tr_cb(); most comments also apply here because this
+ * function does almost the same thing and they work closely
+ * together.
+ *
+ * If the seg request has failed but this phase has succeeded,
+ * wa_seg_tr_cb() has already failed the segment and moved the
+ * status to WA_SEG_ERROR, so this will go through 'case 0' and
+ * effectively do nothing.
+ */
+static void wa_seg_iso_pack_desc_cb(struct urb *urb)
+{
+       struct wa_seg *seg = urb->context;
+       struct wa_xfer *xfer = seg->xfer;
+       struct wahc *wa;
+       struct device *dev;
+       struct wa_rpipe *rpipe;
+       unsigned long flags;
+       unsigned rpipe_ready = 0;
+       u8 done = 0;
+
+       switch (urb->status) {
+       case 0:
+               spin_lock_irqsave(&xfer->lock, flags);
+               wa = xfer->wa;
+               dev = &wa->usb_iface->dev;
+               dev_dbg(dev, "iso xfer %08X#%u: packet descriptor done\n",
+                       wa_xfer_id(xfer), seg->index);
+               if (xfer->is_inbound && seg->status < WA_SEG_PENDING)
+                       seg->status = WA_SEG_PENDING;
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               break;
+       case -ECONNRESET:       /* URB unlinked; no need to do anything */
+       case -ENOENT:           /* as it was done by the who unlinked us */
+               break;
+       default:                /* Other errors ... */
+               spin_lock_irqsave(&xfer->lock, flags);
+               wa = xfer->wa;
+               dev = &wa->usb_iface->dev;
+               rpipe = xfer->ep->hcpriv;
+               pr_err_ratelimited("iso xfer %08X#%u: packet descriptor error %d\n",
+                               wa_xfer_id(xfer), seg->index, urb->status);
+               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+                           EDC_ERROR_TIMEFRAME)){
+                       dev_err(dev, "iso xfer: URB max acceptable errors exceeded, resetting device\n");
+                       wa_reset_all(wa);
+               }
+               if (seg->status != WA_SEG_ERROR) {
+                       usb_unlink_urb(seg->dto_urb);
+                       seg->result = urb->status;
+                       __wa_xfer_abort(xfer);
+                       rpipe_ready = rpipe_avail_inc(rpipe);
+                       done = __wa_xfer_mark_seg_as_done(xfer, seg,
+                                       WA_SEG_ERROR);
+               }
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               if (done)
+                       wa_xfer_completion(xfer);
+               if (rpipe_ready)
+                       wa_xfer_delayed_run(rpipe);
+       }
+       /* taken when this URB was submitted. */
+       wa_xfer_put(xfer);
+}
+
+/*
+ * Callback for the segment request
+ *
+ * If successful transition state (unless already transitioned or
+ * outbound transfer); otherwise, take a note of the error, mark this
+ * segment done and try completion.
+ *
+ * Note we don't access until we are sure that the transfer hasn't
+ * been cancelled (ECONNRESET, ENOENT), which could mean that
+ * seg->xfer could be already gone.
+ *
+ * We have to check before setting the status to WA_SEG_PENDING
+ * because sometimes the xfer result callback arrives before this
+ * callback (geeeeeeze), so it might happen that we are already in
+ * another state. As well, we don't set it if the transfer is not inbound,
+ * as in that case, wa_seg_dto_cb will do it when the OUT data phase
+ * finishes.
+ */
+static void wa_seg_tr_cb(struct urb *urb)
+{
+       struct wa_seg *seg = urb->context;
+       struct wa_xfer *xfer = seg->xfer;
+       struct wahc *wa;
+       struct device *dev;
+       struct wa_rpipe *rpipe;
+       unsigned long flags;
+       unsigned rpipe_ready;
+       u8 done = 0;
+
+       switch (urb->status) {
+       case 0:
+               spin_lock_irqsave(&xfer->lock, flags);
+               wa = xfer->wa;
+               dev = &wa->usb_iface->dev;
+               dev_dbg(dev, "xfer %p ID 0x%08X#%u: request done\n",
+                       xfer, wa_xfer_id(xfer), seg->index);
+               if (xfer->is_inbound &&
+                       seg->status < WA_SEG_PENDING &&
+                       !(usb_pipeisoc(xfer->urb->pipe)))
+                       seg->status = WA_SEG_PENDING;
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               break;
+       case -ECONNRESET:       /* URB unlinked; no need to do anything */
+       case -ENOENT:           /* as it was done by the who unlinked us */
+               break;
+       default:                /* Other errors ... */
+               spin_lock_irqsave(&xfer->lock, flags);
+               wa = xfer->wa;
+               dev = &wa->usb_iface->dev;
+               rpipe = xfer->ep->hcpriv;
+               if (printk_ratelimit())
+                       dev_err(dev, "xfer %p ID 0x%08X#%u: request error %d\n",
+                               xfer, wa_xfer_id(xfer), seg->index,
+                               urb->status);
+               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+                           EDC_ERROR_TIMEFRAME)){
+                       dev_err(dev, "DTO: URB max acceptable errors "
+                               "exceeded, resetting device\n");
+                       wa_reset_all(wa);
+               }
+               usb_unlink_urb(seg->isoc_pack_desc_urb);
+               usb_unlink_urb(seg->dto_urb);
+               seg->result = urb->status;
+               __wa_xfer_abort(xfer);
+               rpipe_ready = rpipe_avail_inc(rpipe);
+               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               if (done)
+                       wa_xfer_completion(xfer);
+               if (rpipe_ready)
+                       wa_xfer_delayed_run(rpipe);
+       }
+       /* taken when this URB was submitted. */
+       wa_xfer_put(xfer);
+}
+
+/*
+ * Allocate an SG list to store bytes_to_transfer bytes and copy the
+ * subset of the in_sg that matches the buffer subset
+ * we are about to transfer.
+ */
+static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,
+       const unsigned int bytes_transferred,
+       const unsigned int bytes_to_transfer, int *out_num_sgs)
+{
+       struct scatterlist *out_sg;
+       unsigned int bytes_processed = 0, offset_into_current_page_data = 0,
+               nents;
+       struct scatterlist *current_xfer_sg = in_sg;
+       struct scatterlist *current_seg_sg, *last_seg_sg;
+
+       /* skip previously transferred pages. */
+       while ((current_xfer_sg) &&
+                       (bytes_processed < bytes_transferred)) {
+               bytes_processed += current_xfer_sg->length;
+
+               /* advance the sg if current segment starts on or past the
+                       next page. */
+               if (bytes_processed <= bytes_transferred)
+                       current_xfer_sg = sg_next(current_xfer_sg);
+       }
+
+       /* the data for the current segment starts in current_xfer_sg.
+               calculate the offset. */
+       if (bytes_processed > bytes_transferred) {
+               offset_into_current_page_data = current_xfer_sg->length -
+                       (bytes_processed - bytes_transferred);
+       }
+
+       /* calculate the number of pages needed by this segment. */
+       nents = DIV_ROUND_UP((bytes_to_transfer +
+               offset_into_current_page_data +
+               current_xfer_sg->offset),
+               PAGE_SIZE);
+
+       out_sg = kmalloc((sizeof(struct scatterlist) * nents), GFP_ATOMIC);
+       if (out_sg) {
+               sg_init_table(out_sg, nents);
+
+               /* copy the portion of the incoming SG that correlates to the
+                * data to be transferred by this segment to the segment SG. */
+               last_seg_sg = current_seg_sg = out_sg;
+               bytes_processed = 0;
+
+               /* reset nents and calculate the actual number of sg entries
+                       needed. */
+               nents = 0;
+               while ((bytes_processed < bytes_to_transfer) &&
+                               current_seg_sg && current_xfer_sg) {
+                       unsigned int page_len = min((current_xfer_sg->length -
+                               offset_into_current_page_data),
+                               (bytes_to_transfer - bytes_processed));
+
+                       sg_set_page(current_seg_sg, sg_page(current_xfer_sg),
+                               page_len,
+                               current_xfer_sg->offset +
+                               offset_into_current_page_data);
+
+                       bytes_processed += page_len;
+
+                       last_seg_sg = current_seg_sg;
+                       current_seg_sg = sg_next(current_seg_sg);
+                       current_xfer_sg = sg_next(current_xfer_sg);
+
+                       /* only the first page may require additional offset. */
+                       offset_into_current_page_data = 0;
+                       nents++;
+               }
+
+               /* update num_sgs and terminate the list since we may have
+                *  concatenated pages. */
+               sg_mark_end(last_seg_sg);
+               *out_num_sgs = nents;
+       }
+
+       return out_sg;
+}
+
+/*
+ * Populate DMA buffer info for the isoc dto urb.
+ */
+static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer,
+       struct wa_seg *seg, int curr_iso_frame)
+{
+       seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+       seg->dto_urb->sg = NULL;
+       seg->dto_urb->num_sgs = 0;
+       /* dto urb buffer address pulled from iso_frame_desc. */
+       seg->dto_urb->transfer_dma = xfer->urb->transfer_dma +
+               xfer->urb->iso_frame_desc[curr_iso_frame].offset;
+       /* The Alereon HWA sends a single URB with all isoc segs. */
+       if (xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
+               seg->dto_urb->transfer_buffer_length = seg->isoc_size;
+       else
+               seg->dto_urb->transfer_buffer_length =
+                       xfer->urb->iso_frame_desc[curr_iso_frame].length;
+}
+
+/*
+ * Populate buffer ptr and size, DMA buffer or SG list for the dto urb.
+ */
+static int __wa_populate_dto_urb(struct wa_xfer *xfer,
+       struct wa_seg *seg, size_t buf_itr_offset, size_t buf_itr_size)
+{
+       int result = 0;
+
+       if (xfer->is_dma) {
+               seg->dto_urb->transfer_dma =
+                       xfer->urb->transfer_dma + buf_itr_offset;
+               seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+               seg->dto_urb->sg = NULL;
+               seg->dto_urb->num_sgs = 0;
+       } else {
+               /* do buffer or SG processing. */
+               seg->dto_urb->transfer_flags &=
+                       ~URB_NO_TRANSFER_DMA_MAP;
+               /* this should always be 0 before a resubmit. */
+               seg->dto_urb->num_mapped_sgs = 0;
+
+               if (xfer->urb->transfer_buffer) {
+                       seg->dto_urb->transfer_buffer =
+                               xfer->urb->transfer_buffer +
+                               buf_itr_offset;
+                       seg->dto_urb->sg = NULL;
+                       seg->dto_urb->num_sgs = 0;
+               } else {
+                       seg->dto_urb->transfer_buffer = NULL;
+
+                       /*
+                        * allocate an SG list to store seg_size bytes
+                        * and copy the subset of the xfer->urb->sg that
+                        * matches the buffer subset we are about to
+                        * read.
+                        */
+                       seg->dto_urb->sg = wa_xfer_create_subset_sg(
+                               xfer->urb->sg,
+                               buf_itr_offset, buf_itr_size,
+                               &(seg->dto_urb->num_sgs));
+                       if (!(seg->dto_urb->sg))
+                               result = -ENOMEM;
+               }
+       }
+       seg->dto_urb->transfer_buffer_length = buf_itr_size;
+
+       return result;
+}
+
+/*
+ * Allocate the segs array and initialize each of them
+ *
+ * The segments are freed by wa_xfer_destroy() when the xfer use count
+ * drops to zero; however, because each segment is given the same life
+ * cycle as the USB URB it contains, it is actually freed by
+ * usb_put_urb() on the contained USB URB (twisted, eh?).
+ */
+static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
+{
+       int result, cnt, isoc_frame_offset = 0;
+       size_t alloc_size = sizeof(*xfer->seg[0])
+               - sizeof(xfer->seg[0]->xfer_hdr) + xfer_hdr_size;
+       struct usb_device *usb_dev = xfer->wa->usb_dev;
+       const struct usb_endpoint_descriptor *dto_epd = xfer->wa->dto_epd;
+       struct wa_seg *seg;
+       size_t buf_itr, buf_size, buf_itr_size;
+
+       result = -ENOMEM;
+       xfer->seg = kcalloc(xfer->segs, sizeof(xfer->seg[0]), GFP_ATOMIC);
+       if (xfer->seg == NULL)
+               goto error_segs_kzalloc;
+       buf_itr = 0;
+       buf_size = xfer->urb->transfer_buffer_length;
+       for (cnt = 0; cnt < xfer->segs; cnt++) {
+               size_t iso_pkt_descr_size = 0;
+               int seg_isoc_frame_count = 0, seg_isoc_size = 0;
+
+               /*
+                * Adjust the size of the segment object to contain space for
+                * the isoc packet descriptor buffer.
+                */
+               if (usb_pipeisoc(xfer->urb->pipe)) {
+                       seg_isoc_frame_count =
+                               __wa_seg_calculate_isoc_frame_count(xfer,
+                                       isoc_frame_offset, &seg_isoc_size);
+
+                       iso_pkt_descr_size =
+                               sizeof(struct wa_xfer_packet_info_hwaiso) +
+                               (seg_isoc_frame_count * sizeof(__le16));
+               }
+               result = -ENOMEM;
+               seg = xfer->seg[cnt] = kmalloc(alloc_size + iso_pkt_descr_size,
+                                               GFP_ATOMIC);
+               if (seg == NULL)
+                       goto error_seg_kmalloc;
+               wa_seg_init(seg);
+               seg->xfer = xfer;
+               seg->index = cnt;
+               usb_fill_bulk_urb(&seg->tr_urb, usb_dev,
+                                 usb_sndbulkpipe(usb_dev,
+                                                 dto_epd->bEndpointAddress),
+                                 &seg->xfer_hdr, xfer_hdr_size,
+                                 wa_seg_tr_cb, seg);
+               buf_itr_size = min(buf_size, xfer->seg_size);
+
+               if (usb_pipeisoc(xfer->urb->pipe)) {
+                       seg->isoc_frame_count = seg_isoc_frame_count;
+                       seg->isoc_frame_offset = isoc_frame_offset;
+                       seg->isoc_size = seg_isoc_size;
+                       /* iso packet descriptor. */
+                       seg->isoc_pack_desc_urb =
+                                       usb_alloc_urb(0, GFP_ATOMIC);
+                       if (seg->isoc_pack_desc_urb == NULL)
+                               goto error_iso_pack_desc_alloc;
+                       /*
+                        * The buffer for the isoc packet descriptor starts
+                        * after the transfer request header in the
+                        * segment object memory buffer.
+                        */
+                       usb_fill_bulk_urb(
+                               seg->isoc_pack_desc_urb, usb_dev,
+                               usb_sndbulkpipe(usb_dev,
+                                       dto_epd->bEndpointAddress),
+                               (void *)(&seg->xfer_hdr) +
+                                       xfer_hdr_size,
+                               iso_pkt_descr_size,
+                               wa_seg_iso_pack_desc_cb, seg);
+
+                       /* adjust starting frame offset for next seg. */
+                       isoc_frame_offset += seg_isoc_frame_count;
+               }
+
+               if (xfer->is_inbound == 0 && buf_size > 0) {
+                       /* outbound data. */
+                       seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC);
+                       if (seg->dto_urb == NULL)
+                               goto error_dto_alloc;
+                       usb_fill_bulk_urb(
+                               seg->dto_urb, usb_dev,
+                               usb_sndbulkpipe(usb_dev,
+                                               dto_epd->bEndpointAddress),
+                               NULL, 0, wa_seg_dto_cb, seg);
+
+                       if (usb_pipeisoc(xfer->urb->pipe)) {
+                               /*
+                                * Fill in the xfer buffer information for the
+                                * first isoc frame.  Subsequent frames in this
+                                * segment will be filled in and sent from the
+                                * DTO completion routine, if needed.
+                                */
+                               __wa_populate_dto_urb_isoc(xfer, seg,
+                                       seg->isoc_frame_offset);
+                       } else {
+                               /* fill in the xfer buffer information. */
+                               result = __wa_populate_dto_urb(xfer, seg,
+                                                       buf_itr, buf_itr_size);
+                               if (result < 0)
+                                       goto error_seg_outbound_populate;
+
+                               buf_itr += buf_itr_size;
+                               buf_size -= buf_itr_size;
+                       }
+               }
+               seg->status = WA_SEG_READY;
+       }
+       return 0;
+
+       /*
+        * Free the memory for the current segment which failed to init.
+        * Use the fact that cnt is left at were it failed.  The remaining
+        * segments will be cleaned up by wa_xfer_destroy.
+        */
+error_seg_outbound_populate:
+       usb_free_urb(xfer->seg[cnt]->dto_urb);
+error_dto_alloc:
+       usb_free_urb(xfer->seg[cnt]->isoc_pack_desc_urb);
+error_iso_pack_desc_alloc:
+       kfree(xfer->seg[cnt]);
+       xfer->seg[cnt] = NULL;
+error_seg_kmalloc:
+error_segs_kzalloc:
+       return result;
+}
+
+/*
+ * Allocates all the stuff needed to submit a transfer
+ *
+ * Breaks the whole data buffer in a list of segments, each one has a
+ * structure allocated to it and linked in xfer->seg[index]
+ *
+ * FIXME: merge setup_segs() and the last part of this function, no
+ *        need to do two for loops when we could run everything in a
+ *        single one
+ */
+static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb)
+{
+       int result;
+       struct device *dev = &xfer->wa->usb_iface->dev;
+       enum wa_xfer_type xfer_type = 0; /* shut up GCC */
+       size_t xfer_hdr_size, cnt, transfer_size;
+       struct wa_xfer_hdr *xfer_hdr0, *xfer_hdr;
+
+       result = __wa_xfer_setup_sizes(xfer, &xfer_type);
+       if (result < 0)
+               goto error_setup_sizes;
+       xfer_hdr_size = result;
+       result = __wa_xfer_setup_segs(xfer, xfer_hdr_size);
+       if (result < 0) {
+               dev_err(dev, "xfer %p: Failed to allocate %d segments: %d\n",
+                       xfer, xfer->segs, result);
+               goto error_setup_segs;
+       }
+       /* Fill the first header */
+       xfer_hdr0 = &xfer->seg[0]->xfer_hdr;
+       wa_xfer_id_init(xfer);
+       __wa_xfer_setup_hdr0(xfer, xfer_hdr0, xfer_type, xfer_hdr_size);
+
+       /* Fill remaining headers */
+       xfer_hdr = xfer_hdr0;
+       if (xfer_type == WA_XFER_TYPE_ISO) {
+               xfer_hdr0->dwTransferLength =
+                       cpu_to_le32(xfer->seg[0]->isoc_size);
+               for (cnt = 1; cnt < xfer->segs; cnt++) {
+                       struct wa_xfer_packet_info_hwaiso *packet_desc;
+                       struct wa_seg *seg = xfer->seg[cnt];
+                       struct wa_xfer_hwaiso *xfer_iso;
+
+                       xfer_hdr = &seg->xfer_hdr;
+                       xfer_iso = container_of(xfer_hdr,
+                                               struct wa_xfer_hwaiso, hdr);
+                       packet_desc = ((void *)xfer_hdr) + xfer_hdr_size;
+                       /*
+                        * Copy values from the 0th header. Segment specific
+                        * values are set below.
+                        */
+                       memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size);
+                       xfer_hdr->bTransferSegment = cnt;
+                       xfer_hdr->dwTransferLength =
+                               cpu_to_le32(seg->isoc_size);
+                       xfer_iso->dwNumOfPackets =
+                                       cpu_to_le32(seg->isoc_frame_count);
+                       __wa_setup_isoc_packet_descr(packet_desc, xfer, seg);
+                       seg->status = WA_SEG_READY;
+               }
+       } else {
+               transfer_size = urb->transfer_buffer_length;
+               xfer_hdr0->dwTransferLength = transfer_size > xfer->seg_size ?
+                       cpu_to_le32(xfer->seg_size) :
+                       cpu_to_le32(transfer_size);
+               transfer_size -=  xfer->seg_size;
+               for (cnt = 1; cnt < xfer->segs; cnt++) {
+                       xfer_hdr = &xfer->seg[cnt]->xfer_hdr;
+                       memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size);
+                       xfer_hdr->bTransferSegment = cnt;
+                       xfer_hdr->dwTransferLength =
+                               transfer_size > xfer->seg_size ?
+                                       cpu_to_le32(xfer->seg_size)
+                                       : cpu_to_le32(transfer_size);
+                       xfer->seg[cnt]->status = WA_SEG_READY;
+                       transfer_size -=  xfer->seg_size;
+               }
+       }
+       xfer_hdr->bTransferSegment |= 0x80;     /* this is the last segment */
+       result = 0;
+error_setup_segs:
+error_setup_sizes:
+       return result;
+}
+
+/*
+ *
+ *
+ * rpipe->seg_lock is held!
+ */
+static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
+                          struct wa_seg *seg, int *dto_done)
+{
+       int result;
+
+       /* default to done unless we encounter a multi-frame isoc segment. */
+       *dto_done = 1;
+
+       /*
+        * Take a ref for each segment urb so the xfer cannot disappear until
+        * all of the callbacks run.
+        */
+       wa_xfer_get(xfer);
+       /* submit the transfer request. */
+       seg->status = WA_SEG_SUBMITTED;
+       result = usb_submit_urb(&seg->tr_urb, GFP_ATOMIC);
+       if (result < 0) {
+               pr_err("%s: xfer %p#%u: REQ submit failed: %d\n",
+                      __func__, xfer, seg->index, result);
+               wa_xfer_put(xfer);
+               goto error_tr_submit;
+       }
+       /* submit the isoc packet descriptor if present. */
+       if (seg->isoc_pack_desc_urb) {
+               wa_xfer_get(xfer);
+               result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC);
+               seg->isoc_frame_index = 0;
+               if (result < 0) {
+                       pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n",
+                              __func__, xfer, seg->index, result);
+                       wa_xfer_put(xfer);
+                       goto error_iso_pack_desc_submit;
+               }
+       }
+       /* submit the out data if this is an out request. */
+       if (seg->dto_urb) {
+               struct wahc *wa = xfer->wa;
+               wa_xfer_get(xfer);
+               result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
+               if (result < 0) {
+                       pr_err("%s: xfer %p#%u: DTO submit failed: %d\n",
+                              __func__, xfer, seg->index, result);
+                       wa_xfer_put(xfer);
+                       goto error_dto_submit;
+               }
+               /*
+                * If this segment contains more than one isoc frame, hold
+                * onto the dto resource until we send all frames.
+                * Only applies to non-Alereon devices.
+                */
+               if (((wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) == 0)
+                       && (seg->isoc_frame_count > 1))
+                       *dto_done = 0;
+       }
+       rpipe_avail_dec(rpipe);
+       return 0;
+
+error_dto_submit:
+       usb_unlink_urb(seg->isoc_pack_desc_urb);
+error_iso_pack_desc_submit:
+       usb_unlink_urb(&seg->tr_urb);
+error_tr_submit:
+       seg->status = WA_SEG_ERROR;
+       seg->result = result;
+       *dto_done = 1;
+       return result;
+}
+
+/*
+ * Execute more queued request segments until the maximum concurrent allowed.
+ * Return true if the DTO resource was acquired and released.
+ *
+ * The ugly unlock/lock sequence on the error path is needed as the
+ * xfer->lock normally nests the seg_lock and not viceversa.
+ */
+static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting)
+{
+       int result, dto_acquired = 0, dto_done = 0;
+       struct device *dev = &rpipe->wa->usb_iface->dev;
+       struct wa_seg *seg;
+       struct wa_xfer *xfer;
+       unsigned long flags;
+
+       *dto_waiting = 0;
+
+       spin_lock_irqsave(&rpipe->seg_lock, flags);
+       while (atomic_read(&rpipe->segs_available) > 0
+             && !list_empty(&rpipe->seg_list)
+             && (dto_acquired = __wa_dto_try_get(rpipe->wa))) {
+               seg = list_first_entry(&(rpipe->seg_list), struct wa_seg,
+                                list_node);
+               list_del(&seg->list_node);
+               xfer = seg->xfer;
+               /*
+                * Get a reference to the xfer in case the callbacks for the
+                * URBs submitted by __wa_seg_submit attempt to complete
+                * the xfer before this function completes.
+                */
+               wa_xfer_get(xfer);
+               result = __wa_seg_submit(rpipe, xfer, seg, &dto_done);
+               /* release the dto resource if this RPIPE is done with it. */
+               if (dto_done)
+                       __wa_dto_put(rpipe->wa);
+               dev_dbg(dev, "xfer %p ID %08X#%u submitted from delayed [%d segments available] %d\n",
+                       xfer, wa_xfer_id(xfer), seg->index,
+                       atomic_read(&rpipe->segs_available), result);
+               if (unlikely(result < 0)) {
+                       int done;
+
+                       spin_unlock_irqrestore(&rpipe->seg_lock, flags);
+                       spin_lock_irqsave(&xfer->lock, flags);
+                       __wa_xfer_abort(xfer);
+                       /*
+                        * This seg was marked as submitted when it was put on
+                        * the RPIPE seg_list.  Mark it done.
+                        */
+                       xfer->segs_done++;
+                       done = __wa_xfer_is_done(xfer);
+                       spin_unlock_irqrestore(&xfer->lock, flags);
+                       if (done)
+                               wa_xfer_completion(xfer);
+                       spin_lock_irqsave(&rpipe->seg_lock, flags);
+               }
+               wa_xfer_put(xfer);
+       }
+       /*
+        * Mark this RPIPE as waiting if dto was not acquired, there are
+        * delayed segs and no active transfers to wake us up later.
+        */
+       if (!dto_acquired && !list_empty(&rpipe->seg_list)
+               && (atomic_read(&rpipe->segs_available) ==
+                       le16_to_cpu(rpipe->descr.wRequests)))
+               *dto_waiting = 1;
+
+       spin_unlock_irqrestore(&rpipe->seg_lock, flags);
+
+       return dto_done;
+}
+
+static void wa_xfer_delayed_run(struct wa_rpipe *rpipe)
+{
+       int dto_waiting;
+       int dto_done = __wa_xfer_delayed_run(rpipe, &dto_waiting);
+
+       /*
+        * If this RPIPE is waiting on the DTO resource, add it to the tail of
+        * the waiting list.
+        * Otherwise, if the WA DTO resource was acquired and released by
+        *  __wa_xfer_delayed_run, another RPIPE may have attempted to acquire
+        * DTO and failed during that time.  Check the delayed list and process
+        * any waiters.  Start searching from the next RPIPE index.
+        */
+       if (dto_waiting)
+               wa_add_delayed_rpipe(rpipe->wa, rpipe);
+       else if (dto_done)
+               wa_check_for_delayed_rpipes(rpipe->wa);
+}
+
+/*
+ *
+ * xfer->lock is taken
+ *
+ * On failure submitting we just stop submitting and return error;
+ * wa_urb_enqueue_b() will execute the completion path
+ */
+static int __wa_xfer_submit(struct wa_xfer *xfer)
+{
+       int result, dto_acquired = 0, dto_done = 0, dto_waiting = 0;
+       struct wahc *wa = xfer->wa;
+       struct device *dev = &wa->usb_iface->dev;
+       unsigned cnt;
+       struct wa_seg *seg;
+       unsigned long flags;
+       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+       size_t maxrequests = le16_to_cpu(rpipe->descr.wRequests);
+       u8 available;
+       u8 empty;
+
+       spin_lock_irqsave(&wa->xfer_list_lock, flags);
+       list_add_tail(&xfer->list_node, &wa->xfer_list);
+       spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
+
+       BUG_ON(atomic_read(&rpipe->segs_available) > maxrequests);
+       result = 0;
+       spin_lock_irqsave(&rpipe->seg_lock, flags);
+       for (cnt = 0; cnt < xfer->segs; cnt++) {
+               int delay_seg = 1;
+
+               available = atomic_read(&rpipe->segs_available);
+               empty = list_empty(&rpipe->seg_list);
+               seg = xfer->seg[cnt];
+               if (available && empty) {
+                       /*
+                        * Only attempt to acquire DTO if we have a segment
+                        * to send.
+                        */
+                       dto_acquired = __wa_dto_try_get(rpipe->wa);
+                       if (dto_acquired) {
+                               delay_seg = 0;
+                               result = __wa_seg_submit(rpipe, xfer, seg,
+                                                       &dto_done);
+                               dev_dbg(dev, "xfer %p ID 0x%08X#%u: available %u empty %u submitted\n",
+                                       xfer, wa_xfer_id(xfer), cnt, available,
+                                       empty);
+                               if (dto_done)
+                                       __wa_dto_put(rpipe->wa);
+
+                               if (result < 0) {
+                                       __wa_xfer_abort(xfer);
+                                       goto error_seg_submit;
+                               }
+                       }
+               }
+
+               if (delay_seg) {
+                       dev_dbg(dev, "xfer %p ID 0x%08X#%u: available %u empty %u delayed\n",
+                               xfer, wa_xfer_id(xfer), cnt, available,  empty);
+                       seg->status = WA_SEG_DELAYED;
+                       list_add_tail(&seg->list_node, &rpipe->seg_list);
+               }
+               xfer->segs_submitted++;
+       }
+error_seg_submit:
+       /*
+        * Mark this RPIPE as waiting if dto was not acquired, there are
+        * delayed segs and no active transfers to wake us up later.
+        */
+       if (!dto_acquired && !list_empty(&rpipe->seg_list)
+               && (atomic_read(&rpipe->segs_available) ==
+                       le16_to_cpu(rpipe->descr.wRequests)))
+               dto_waiting = 1;
+       spin_unlock_irqrestore(&rpipe->seg_lock, flags);
+
+       if (dto_waiting)
+               wa_add_delayed_rpipe(rpipe->wa, rpipe);
+       else if (dto_done)
+               wa_check_for_delayed_rpipes(rpipe->wa);
+
+       return result;
+}
+
+/*
+ * Second part of a URB/transfer enqueuement
+ *
+ * Assumes this comes from wa_urb_enqueue() [maybe through
+ * wa_urb_enqueue_run()]. At this point:
+ *
+ * xfer->wa    filled and refcounted
+ * xfer->ep    filled with rpipe refcounted if
+ *              delayed == 0
+ * xfer->urb   filled and refcounted (this is the case when called
+ *              from wa_urb_enqueue() as we come from usb_submit_urb()
+ *              and when called by wa_urb_enqueue_run(), as we took an
+ *              extra ref dropped by _run() after we return).
+ * xfer->gfp   filled
+ *
+ * If we fail at __wa_xfer_submit(), then we just check if we are done
+ * and if so, we run the completion procedure. However, if we are not
+ * yet done, we do nothing and wait for the completion handlers from
+ * the submitted URBs or from the xfer-result path to kick in. If xfer
+ * result never kicks in, the xfer will timeout from the USB code and
+ * dequeue() will be called.
+ */
+static int wa_urb_enqueue_b(struct wa_xfer *xfer)
+{
+       int result;
+       unsigned long flags;
+       struct urb *urb = xfer->urb;
+       struct wahc *wa = xfer->wa;
+       struct wusbhc *wusbhc = wa->wusb;
+       struct wusb_dev *wusb_dev;
+       unsigned done;
+
+       result = rpipe_get_by_ep(wa, xfer->ep, urb, xfer->gfp);
+       if (result < 0) {
+               pr_err("%s: error_rpipe_get\n", __func__);
+               goto error_rpipe_get;
+       }
+       result = -ENODEV;
+       /* FIXME: segmentation broken -- kills DWA */
+       mutex_lock(&wusbhc->mutex);             /* get a WUSB dev */
+       if (urb->dev == NULL) {
+               mutex_unlock(&wusbhc->mutex);
+               pr_err("%s: error usb dev gone\n", __func__);
+               goto error_dev_gone;
+       }
+       wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev);
+       if (wusb_dev == NULL) {
+               mutex_unlock(&wusbhc->mutex);
+               dev_err(&(urb->dev->dev), "%s: error wusb dev gone\n",
+                       __func__);
+               goto error_dev_gone;
+       }
+       mutex_unlock(&wusbhc->mutex);
+
+       spin_lock_irqsave(&xfer->lock, flags);
+       xfer->wusb_dev = wusb_dev;
+       result = urb->status;
+       if (urb->status != -EINPROGRESS) {
+               dev_err(&(urb->dev->dev), "%s: error_dequeued\n", __func__);
+               goto error_dequeued;
+       }
+
+       result = __wa_xfer_setup(xfer, urb);
+       if (result < 0) {
+               dev_err(&(urb->dev->dev), "%s: error_xfer_setup\n", __func__);
+               goto error_xfer_setup;
+       }
+       /*
+        * Get a xfer reference since __wa_xfer_submit starts asynchronous
+        * operations that may try to complete the xfer before this function
+        * exits.
+        */
+       wa_xfer_get(xfer);
+       result = __wa_xfer_submit(xfer);
+       if (result < 0) {
+               dev_err(&(urb->dev->dev), "%s: error_xfer_submit\n", __func__);
+               goto error_xfer_submit;
+       }
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       wa_xfer_put(xfer);
+       return 0;
+
+       /*
+        * this is basically wa_xfer_completion() broken up wa_xfer_giveback()
+        * does a wa_xfer_put() that will call wa_xfer_destroy() and undo
+        * setup().
+        */
+error_xfer_setup:
+error_dequeued:
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       /* FIXME: segmentation broken, kills DWA */
+       if (wusb_dev)
+               wusb_dev_put(wusb_dev);
+error_dev_gone:
+       rpipe_put(xfer->ep->hcpriv);
+error_rpipe_get:
+       xfer->result = result;
+       return result;
+
+error_xfer_submit:
+       done = __wa_xfer_is_done(xfer);
+       xfer->result = result;
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       if (done)
+               wa_xfer_completion(xfer);
+       wa_xfer_put(xfer);
+       /* return success since the completion routine will run. */
+       return 0;
+}
+
+/*
+ * Execute the delayed transfers in the Wire Adapter @wa
+ *
+ * We need to be careful here, as dequeue() could be called in the
+ * middle.  That's why we do the whole thing under the
+ * wa->xfer_list_lock. If dequeue() jumps in, it first locks xfer->lock
+ * and then checks the list -- so as we would be acquiring in inverse
+ * order, we move the delayed list to a separate list while locked and then
+ * submit them without the list lock held.
+ */
+void wa_urb_enqueue_run(struct work_struct *ws)
+{
+       struct wahc *wa = container_of(ws, struct wahc, xfer_enqueue_work);
+       struct wa_xfer *xfer, *next;
+       struct urb *urb;
+       LIST_HEAD(tmp_list);
+
+       /* Create a copy of the wa->xfer_delayed_list while holding the lock */
+       spin_lock_irq(&wa->xfer_list_lock);
+       list_cut_position(&tmp_list, &wa->xfer_delayed_list,
+                       wa->xfer_delayed_list.prev);
+       spin_unlock_irq(&wa->xfer_list_lock);
+
+       /*
+        * enqueue from temp list without list lock held since wa_urb_enqueue_b
+        * can take xfer->lock as well as lock mutexes.
+        */
+       list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
+               list_del_init(&xfer->list_node);
+
+               urb = xfer->urb;
+               if (wa_urb_enqueue_b(xfer) < 0)
+                       wa_xfer_giveback(xfer);
+               usb_put_urb(urb);       /* taken when queuing */
+       }
+}
+EXPORT_SYMBOL_GPL(wa_urb_enqueue_run);
+
+/*
+ * Process the errored transfers on the Wire Adapter outside of interrupt.
+ */
+void wa_process_errored_transfers_run(struct work_struct *ws)
+{
+       struct wahc *wa = container_of(ws, struct wahc, xfer_error_work);
+       struct wa_xfer *xfer, *next;
+       LIST_HEAD(tmp_list);
+
+       pr_info("%s: Run delayed STALL processing.\n", __func__);
+
+       /* Create a copy of the wa->xfer_errored_list while holding the lock */
+       spin_lock_irq(&wa->xfer_list_lock);
+       list_cut_position(&tmp_list, &wa->xfer_errored_list,
+                       wa->xfer_errored_list.prev);
+       spin_unlock_irq(&wa->xfer_list_lock);
+
+       /*
+        * run rpipe_clear_feature_stalled from temp list without list lock
+        * held.
+        */
+       list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
+               struct usb_host_endpoint *ep;
+               unsigned long flags;
+               struct wa_rpipe *rpipe;
+
+               spin_lock_irqsave(&xfer->lock, flags);
+               ep = xfer->ep;
+               rpipe = ep->hcpriv;
+               spin_unlock_irqrestore(&xfer->lock, flags);
+
+               /* clear RPIPE feature stalled without holding a lock. */
+               rpipe_clear_feature_stalled(wa, ep);
+
+               /* complete the xfer. This removes it from the tmp list. */
+               wa_xfer_completion(xfer);
+
+               /* check for work. */
+               wa_xfer_delayed_run(rpipe);
+       }
+}
+EXPORT_SYMBOL_GPL(wa_process_errored_transfers_run);
+
+/*
+ * Submit a transfer to the Wire Adapter in a delayed way
+ *
+ * The process of enqueuing involves possible sleeps() [see
+ * enqueue_b(), for the rpipe_get() and the mutex_lock()]. If we are
+ * in an atomic section, we defer the enqueue_b() call--else we call direct.
+ *
+ * @urb: We own a reference to it done by the HCI Linux USB stack that
+ *       will be given up by calling usb_hcd_giveback_urb() or by
+ *       returning error from this function -> ergo we don't have to
+ *       refcount it.
+ */
+int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,
+                  struct urb *urb, gfp_t gfp)
+{
+       int result;
+       struct device *dev = &wa->usb_iface->dev;
+       struct wa_xfer *xfer;
+       unsigned long my_flags;
+       unsigned cant_sleep = irqs_disabled() | in_atomic();
+
+       if ((urb->transfer_buffer == NULL)
+           && (urb->sg == NULL)
+           && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
+           && urb->transfer_buffer_length != 0) {
+               dev_err(dev, "BUG? urb %p: NULL xfer buffer & NODMA\n", urb);
+               dump_stack();
+       }
+
+       spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
+       result = usb_hcd_link_urb_to_ep(&(wa->wusb->usb_hcd), urb);
+       spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
+       if (result < 0)
+               goto error_link_urb;
+
+       result = -ENOMEM;
+       xfer = kzalloc(sizeof(*xfer), gfp);
+       if (xfer == NULL)
+               goto error_kmalloc;
+
+       result = -ENOENT;
+       if (urb->status != -EINPROGRESS)        /* cancelled */
+               goto error_dequeued;            /* before starting? */
+       wa_xfer_init(xfer);
+       xfer->wa = wa_get(wa);
+       xfer->urb = urb;
+       xfer->gfp = gfp;
+       xfer->ep = ep;
+       urb->hcpriv = xfer;
+
+       dev_dbg(dev, "xfer %p urb %p pipe 0x%02x [%d bytes] %s %s %s\n",
+               xfer, urb, urb->pipe, urb->transfer_buffer_length,
+               urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? "dma" : "nodma",
+               urb->pipe & USB_DIR_IN ? "inbound" : "outbound",
+               cant_sleep ? "deferred" : "inline");
+
+       if (cant_sleep) {
+               usb_get_urb(urb);
+               spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
+               list_add_tail(&xfer->list_node, &wa->xfer_delayed_list);
+               spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
+               queue_work(wusbd, &wa->xfer_enqueue_work);
+       } else {
+               result = wa_urb_enqueue_b(xfer);
+               if (result < 0) {
+                       /*
+                        * URB submit/enqueue failed.  Clean up, return an
+                        * error and do not run the callback.  This avoids
+                        * an infinite submit/complete loop.
+                        */
+                       dev_err(dev, "%s: URB enqueue failed: %d\n",
+                          __func__, result);
+                       wa_put(xfer->wa);
+                       wa_xfer_put(xfer);
+                       spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
+                       usb_hcd_unlink_urb_from_ep(&(wa->wusb->usb_hcd), urb);
+                       spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
+                       return result;
+               }
+       }
+       return 0;
+
+error_dequeued:
+       kfree(xfer);
+error_kmalloc:
+       spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
+       usb_hcd_unlink_urb_from_ep(&(wa->wusb->usb_hcd), urb);
+       spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
+error_link_urb:
+       return result;
+}
+EXPORT_SYMBOL_GPL(wa_urb_enqueue);
+
+/*
+ * Dequeue a URB and make sure uwb_hcd_giveback_urb() [completion
+ * handler] is called.
+ *
+ * Until a transfer goes successfully through wa_urb_enqueue() it
+ * needs to be dequeued with completion calling; when stuck in delayed
+ * or before wa_xfer_setup() is called, we need to do completion.
+ *
+ *  not setup  If there is no hcpriv yet, that means that that enqueue
+ *             still had no time to set the xfer up. Because
+ *             urb->status should be other than -EINPROGRESS,
+ *             enqueue() will catch that and bail out.
+ *
+ * If the transfer has gone through setup, we just need to clean it
+ * up. If it has gone through submit(), we have to abort it [with an
+ * asynch request] and then make sure we cancel each segment.
+ *
+ */
+int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
+{
+       unsigned long flags;
+       struct wa_xfer *xfer;
+       struct wa_seg *seg;
+       struct wa_rpipe *rpipe;
+       unsigned cnt, done = 0, xfer_abort_pending;
+       unsigned rpipe_ready = 0;
+       int result;
+
+       /* check if it is safe to unlink. */
+       spin_lock_irqsave(&wa->xfer_list_lock, flags);
+       result = usb_hcd_check_unlink_urb(&(wa->wusb->usb_hcd), urb, status);
+       if ((result == 0) && urb->hcpriv) {
+               /*
+                * Get a xfer ref to prevent a race with wa_xfer_giveback
+                * cleaning up the xfer while we are working with it.
+                */
+               wa_xfer_get(urb->hcpriv);
+       }
+       spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
+       if (result)
+               return result;
+
+       xfer = urb->hcpriv;
+       if (xfer == NULL)
+               return -ENOENT;
+       spin_lock_irqsave(&xfer->lock, flags);
+       pr_debug("%s: DEQUEUE xfer id 0x%08X\n", __func__, wa_xfer_id(xfer));
+       rpipe = xfer->ep->hcpriv;
+       if (rpipe == NULL) {
+               pr_debug("%s: xfer %p id 0x%08X has no RPIPE.  %s",
+                       __func__, xfer, wa_xfer_id(xfer),
+                       "Probably already aborted.\n" );
+               result = -ENOENT;
+               goto out_unlock;
+       }
+       /*
+        * Check for done to avoid racing with wa_xfer_giveback and completing
+        * twice.
+        */
+       if (__wa_xfer_is_done(xfer)) {
+               pr_debug("%s: xfer %p id 0x%08X already done.\n", __func__,
+                       xfer, wa_xfer_id(xfer));
+               result = -ENOENT;
+               goto out_unlock;
+       }
+       /* Check the delayed list -> if there, release and complete */
+       spin_lock(&wa->xfer_list_lock);
+       if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
+               goto dequeue_delayed;
+       spin_unlock(&wa->xfer_list_lock);
+       if (xfer->seg == NULL)          /* still hasn't reached */
+               goto out_unlock;        /* setup(), enqueue_b() completes */
+       /* Ok, the xfer is in flight already, it's been setup and submitted.*/
+       xfer_abort_pending = __wa_xfer_abort(xfer) >= 0;
+       /*
+        * grab the rpipe->seg_lock here to prevent racing with
+        * __wa_xfer_delayed_run.
+        */
+       spin_lock(&rpipe->seg_lock);
+       for (cnt = 0; cnt < xfer->segs; cnt++) {
+               seg = xfer->seg[cnt];
+               pr_debug("%s: xfer id 0x%08X#%d status = %d\n",
+                       __func__, wa_xfer_id(xfer), cnt, seg->status);
+               switch (seg->status) {
+               case WA_SEG_NOTREADY:
+               case WA_SEG_READY:
+                       printk(KERN_ERR "xfer %p#%u: dequeue bad state %u\n",
+                              xfer, cnt, seg->status);
+                       WARN_ON(1);
+                       break;
+               case WA_SEG_DELAYED:
+                       /*
+                        * delete from rpipe delayed list.  If no segments on
+                        * this xfer have been submitted, __wa_xfer_is_done will
+                        * trigger a giveback below.  Otherwise, the submitted
+                        * segments will be completed in the DTI interrupt.
+                        */
+                       seg->status = WA_SEG_ABORTED;
+                       seg->result = -ENOENT;
+                       list_del(&seg->list_node);
+                       xfer->segs_done++;
+                       break;
+               case WA_SEG_DONE:
+               case WA_SEG_ERROR:
+               case WA_SEG_ABORTED:
+                       break;
+                       /*
+                        * The buf_in data for a segment in the
+                        * WA_SEG_DTI_PENDING state is actively being read.
+                        * Let wa_buf_in_cb handle it since it will be called
+                        * and will increment xfer->segs_done.  Cleaning up
+                        * here could cause wa_buf_in_cb to access the xfer
+                        * after it has been completed/freed.
+                        */
+               case WA_SEG_DTI_PENDING:
+                       break;
+                       /*
+                        * In the states below, the HWA device already knows
+                        * about the transfer.  If an abort request was sent,
+                        * allow the HWA to process it and wait for the
+                        * results.  Otherwise, the DTI state and seg completed
+                        * counts can get out of sync.
+                        */
+               case WA_SEG_SUBMITTED:
+               case WA_SEG_PENDING:
+                       /*
+                        * Check if the abort was successfully sent.  This could
+                        * be false if the HWA has been removed but we haven't
+                        * gotten the disconnect notification yet.
+                        */
+                       if (!xfer_abort_pending) {
+                               seg->status = WA_SEG_ABORTED;
+                               rpipe_ready = rpipe_avail_inc(rpipe);
+                               xfer->segs_done++;
+                       }
+                       break;
+               }
+       }
+       spin_unlock(&rpipe->seg_lock);
+       xfer->result = urb->status;     /* -ENOENT or -ECONNRESET */
+       done = __wa_xfer_is_done(xfer);
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       if (done)
+               wa_xfer_completion(xfer);
+       if (rpipe_ready)
+               wa_xfer_delayed_run(rpipe);
+       wa_xfer_put(xfer);
+       return result;
+
+out_unlock:
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       wa_xfer_put(xfer);
+       return result;
+
+dequeue_delayed:
+       list_del_init(&xfer->list_node);
+       spin_unlock(&wa->xfer_list_lock);
+       xfer->result = urb->status;
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       wa_xfer_giveback(xfer);
+       wa_xfer_put(xfer);
+       usb_put_urb(urb);               /* we got a ref in enqueue() */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(wa_urb_dequeue);
+
+/*
+ * Translation from WA status codes (WUSB1.0 Table 8.15) to errno
+ * codes
+ *
+ * Positive errno values are internal inconsistencies and should be
+ * flagged louder. Negative are to be passed up to the user in the
+ * normal way.
+ *
+ * @status: USB WA status code -- high two bits are stripped.
+ */
+static int wa_xfer_status_to_errno(u8 status)
+{
+       int errno;
+       u8 real_status = status;
+       static int xlat[] = {
+               [WA_XFER_STATUS_SUCCESS] =              0,
+               [WA_XFER_STATUS_HALTED] =               -EPIPE,
+               [WA_XFER_STATUS_DATA_BUFFER_ERROR] =    -ENOBUFS,
+               [WA_XFER_STATUS_BABBLE] =               -EOVERFLOW,
+               [WA_XFER_RESERVED] =                    EINVAL,
+               [WA_XFER_STATUS_NOT_FOUND] =            0,
+               [WA_XFER_STATUS_INSUFFICIENT_RESOURCE] = -ENOMEM,
+               [WA_XFER_STATUS_TRANSACTION_ERROR] =    -EILSEQ,
+               [WA_XFER_STATUS_ABORTED] =              -ENOENT,
+               [WA_XFER_STATUS_RPIPE_NOT_READY] =      EINVAL,
+               [WA_XFER_INVALID_FORMAT] =              EINVAL,
+               [WA_XFER_UNEXPECTED_SEGMENT_NUMBER] =   EINVAL,
+               [WA_XFER_STATUS_RPIPE_TYPE_MISMATCH] =  EINVAL,
+       };
+       status &= 0x3f;
+
+       if (status == 0)
+               return 0;
+       if (status >= ARRAY_SIZE(xlat)) {
+               printk_ratelimited(KERN_ERR "%s(): BUG? "
+                              "Unknown WA transfer status 0x%02x\n",
+                              __func__, real_status);
+               return -EINVAL;
+       }
+       errno = xlat[status];
+       if (unlikely(errno > 0)) {
+               printk_ratelimited(KERN_ERR "%s(): BUG? "
+                              "Inconsistent WA status: 0x%02x\n",
+                              __func__, real_status);
+               errno = -errno;
+       }
+       return errno;
+}
+
+/*
+ * If a last segment flag and/or a transfer result error is encountered,
+ * no other segment transfer results will be returned from the device.
+ * Mark the remaining submitted or pending xfers as completed so that
+ * the xfer will complete cleanly.
+ *
+ * xfer->lock must be held
+ *
+ */
+static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
+               int starting_index, enum wa_seg_status status)
+{
+       int index;
+       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
+
+       for (index = starting_index; index < xfer->segs_submitted; index++) {
+               struct wa_seg *current_seg = xfer->seg[index];
+
+               BUG_ON(current_seg == NULL);
+
+               switch (current_seg->status) {
+               case WA_SEG_SUBMITTED:
+               case WA_SEG_PENDING:
+               case WA_SEG_DTI_PENDING:
+                       rpipe_avail_inc(rpipe);
+               /*
+                * do not increment RPIPE avail for the WA_SEG_DELAYED case
+                * since it has not been submitted to the RPIPE.
+                */
+               /* fall through */
+               case WA_SEG_DELAYED:
+                       xfer->segs_done++;
+                       current_seg->status = status;
+                       break;
+               case WA_SEG_ABORTED:
+                       break;
+               default:
+                       WARN(1, "%s: xfer 0x%08X#%d. bad seg status = %d\n",
+                               __func__, wa_xfer_id(xfer), index,
+                               current_seg->status);
+                       break;
+               }
+       }
+}
+
+/* Populate the given urb based on the current isoc transfer state. */
+static int __wa_populate_buf_in_urb_isoc(struct wahc *wa,
+       struct urb *buf_in_urb, struct wa_xfer *xfer, struct wa_seg *seg)
+{
+       int urb_start_frame = seg->isoc_frame_index + seg->isoc_frame_offset;
+       int seg_index, total_len = 0, urb_frame_index = urb_start_frame;
+       struct usb_iso_packet_descriptor *iso_frame_desc =
+                                               xfer->urb->iso_frame_desc;
+       const int dti_packet_size = usb_endpoint_maxp(wa->dti_epd);
+       int next_frame_contiguous;
+       struct usb_iso_packet_descriptor *iso_frame;
+
+       BUG_ON(buf_in_urb->status == -EINPROGRESS);
+
+       /*
+        * If the current frame actual_length is contiguous with the next frame
+        * and actual_length is a multiple of the DTI endpoint max packet size,
+        * combine the current frame with the next frame in a single URB.  This
+        * reduces the number of URBs that must be submitted in that case.
+        */
+       seg_index = seg->isoc_frame_index;
+       do {
+               next_frame_contiguous = 0;
+
+               iso_frame = &iso_frame_desc[urb_frame_index];
+               total_len += iso_frame->actual_length;
+               ++urb_frame_index;
+               ++seg_index;
+
+               if (seg_index < seg->isoc_frame_count) {
+                       struct usb_iso_packet_descriptor *next_iso_frame;
+
+                       next_iso_frame = &iso_frame_desc[urb_frame_index];
+
+                       if ((iso_frame->offset + iso_frame->actual_length) ==
+                               next_iso_frame->offset)
+                               next_frame_contiguous = 1;
+               }
+       } while (next_frame_contiguous
+                       && ((iso_frame->actual_length % dti_packet_size) == 0));
+
+       /* this should always be 0 before a resubmit. */
+       buf_in_urb->num_mapped_sgs      = 0;
+       buf_in_urb->transfer_dma = xfer->urb->transfer_dma +
+               iso_frame_desc[urb_start_frame].offset;
+       buf_in_urb->transfer_buffer_length = total_len;
+       buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+       buf_in_urb->transfer_buffer = NULL;
+       buf_in_urb->sg = NULL;
+       buf_in_urb->num_sgs = 0;
+       buf_in_urb->context = seg;
+
+       /* return the number of frames included in this URB. */
+       return seg_index - seg->isoc_frame_index;
+}
+
+/* Populate the given urb based on the current transfer state. */
+static int wa_populate_buf_in_urb(struct urb *buf_in_urb, struct wa_xfer *xfer,
+       unsigned int seg_idx, unsigned int bytes_transferred)
+{
+       int result = 0;
+       struct wa_seg *seg = xfer->seg[seg_idx];
+
+       BUG_ON(buf_in_urb->status == -EINPROGRESS);
+       /* this should always be 0 before a resubmit. */
+       buf_in_urb->num_mapped_sgs      = 0;
+
+       if (xfer->is_dma) {
+               buf_in_urb->transfer_dma = xfer->urb->transfer_dma
+                       + (seg_idx * xfer->seg_size);
+               buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+               buf_in_urb->transfer_buffer = NULL;
+               buf_in_urb->sg = NULL;
+               buf_in_urb->num_sgs = 0;
+       } else {
+               /* do buffer or SG processing. */
+               buf_in_urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP;
+
+               if (xfer->urb->transfer_buffer) {
+                       buf_in_urb->transfer_buffer =
+                               xfer->urb->transfer_buffer
+                               + (seg_idx * xfer->seg_size);
+                       buf_in_urb->sg = NULL;
+                       buf_in_urb->num_sgs = 0;
+               } else {
+                       /* allocate an SG list to store seg_size bytes
+                               and copy the subset of the xfer->urb->sg
+                               that matches the buffer subset we are
+                               about to read. */
+                       buf_in_urb->sg = wa_xfer_create_subset_sg(
+                               xfer->urb->sg,
+                               seg_idx * xfer->seg_size,
+                               bytes_transferred,
+                               &(buf_in_urb->num_sgs));
+
+                       if (!(buf_in_urb->sg)) {
+                               buf_in_urb->num_sgs     = 0;
+                               result = -ENOMEM;
+                       }
+                       buf_in_urb->transfer_buffer = NULL;
+               }
+       }
+       buf_in_urb->transfer_buffer_length = bytes_transferred;
+       buf_in_urb->context = seg;
+
+       return result;
+}
+
+/*
+ * Process a xfer result completion message
+ *
+ * inbound transfers: need to schedule a buf_in_urb read
+ *
+ * FIXME: this function needs to be broken up in parts
+ */
+static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer,
+               struct wa_xfer_result *xfer_result)
+{
+       int result;
+       struct device *dev = &wa->usb_iface->dev;
+       unsigned long flags;
+       unsigned int seg_idx;
+       struct wa_seg *seg;
+       struct wa_rpipe *rpipe;
+       unsigned done = 0;
+       u8 usb_status;
+       unsigned rpipe_ready = 0;
+       unsigned bytes_transferred = le32_to_cpu(xfer_result->dwTransferLength);
+       struct urb *buf_in_urb = &(wa->buf_in_urbs[0]);
+
+       spin_lock_irqsave(&xfer->lock, flags);
+       seg_idx = xfer_result->bTransferSegment & 0x7f;
+       if (unlikely(seg_idx >= xfer->segs))
+               goto error_bad_seg;
+       seg = xfer->seg[seg_idx];
+       rpipe = xfer->ep->hcpriv;
+       usb_status = xfer_result->bTransferStatus;
+       dev_dbg(dev, "xfer %p ID 0x%08X#%u: bTransferStatus 0x%02x (seg status %u)\n",
+               xfer, wa_xfer_id(xfer), seg_idx, usb_status, seg->status);
+       if (seg->status == WA_SEG_ABORTED
+           || seg->status == WA_SEG_ERROR)     /* already handled */
+               goto segment_aborted;
+       if (seg->status == WA_SEG_SUBMITTED)    /* ops, got here */
+               seg->status = WA_SEG_PENDING;   /* before wa_seg{_dto}_cb() */
+       if (seg->status != WA_SEG_PENDING) {
+               if (printk_ratelimit())
+                       dev_err(dev, "xfer %p#%u: Bad segment state %u\n",
+                               xfer, seg_idx, seg->status);
+               seg->status = WA_SEG_PENDING;   /* workaround/"fix" it */
+       }
+       if (usb_status & 0x80) {
+               seg->result = wa_xfer_status_to_errno(usb_status);
+               dev_err(dev, "DTI: xfer %p 0x%08X:#%u failed (0x%02x)\n",
+                       xfer, xfer->id, seg->index, usb_status);
+               seg->status = ((usb_status & 0x7F) == WA_XFER_STATUS_ABORTED) ?
+                       WA_SEG_ABORTED : WA_SEG_ERROR;
+               goto error_complete;
+       }
+       /* FIXME: we ignore warnings, tally them for stats */
+       if (usb_status & 0x40)          /* Warning?... */
+               usb_status = 0;         /* ... pass */
+       /*
+        * If the last segment bit is set, complete the remaining segments.
+        * When the current segment is completed, either in wa_buf_in_cb for
+        * transfers with data or below for no data, the xfer will complete.
+        */
+       if (xfer_result->bTransferSegment & 0x80)
+               wa_complete_remaining_xfer_segs(xfer, seg->index + 1,
+                       WA_SEG_DONE);
+       if (usb_pipeisoc(xfer->urb->pipe)
+               && (le32_to_cpu(xfer_result->dwNumOfPackets) > 0)) {
+               /* set up WA state to read the isoc packet status next. */
+               wa->dti_isoc_xfer_in_progress = wa_xfer_id(xfer);
+               wa->dti_isoc_xfer_seg = seg_idx;
+               wa->dti_state = WA_DTI_ISOC_PACKET_STATUS_PENDING;
+       } else if (xfer->is_inbound && !usb_pipeisoc(xfer->urb->pipe)
+                       && (bytes_transferred > 0)) {
+               /* IN data phase: read to buffer */
+               seg->status = WA_SEG_DTI_PENDING;
+               result = wa_populate_buf_in_urb(buf_in_urb, xfer, seg_idx,
+                       bytes_transferred);
+               if (result < 0)
+                       goto error_buf_in_populate;
+               ++(wa->active_buf_in_urbs);
+               result = usb_submit_urb(buf_in_urb, GFP_ATOMIC);
+               if (result < 0) {
+                       --(wa->active_buf_in_urbs);
+                       goto error_submit_buf_in;
+               }
+       } else {
+               /* OUT data phase or no data, complete it -- */
+               seg->result = bytes_transferred;
+               rpipe_ready = rpipe_avail_inc(rpipe);
+               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);
+       }
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       if (done)
+               wa_xfer_completion(xfer);
+       if (rpipe_ready)
+               wa_xfer_delayed_run(rpipe);
+       return;
+
+error_submit_buf_in:
+       if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+               dev_err(dev, "DTI: URB max acceptable errors "
+                       "exceeded, resetting device\n");
+               wa_reset_all(wa);
+       }
+       if (printk_ratelimit())
+               dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n",
+                       xfer, seg_idx, result);
+       seg->result = result;
+       kfree(buf_in_urb->sg);
+       buf_in_urb->sg = NULL;
+error_buf_in_populate:
+       __wa_xfer_abort(xfer);
+       seg->status = WA_SEG_ERROR;
+error_complete:
+       xfer->segs_done++;
+       rpipe_ready = rpipe_avail_inc(rpipe);
+       wa_complete_remaining_xfer_segs(xfer, seg->index + 1, seg->status);
+       done = __wa_xfer_is_done(xfer);
+       /*
+        * queue work item to clear STALL for control endpoints.
+        * Otherwise, let endpoint_reset take care of it.
+        */
+       if (((usb_status & 0x3f) == WA_XFER_STATUS_HALTED) &&
+               usb_endpoint_xfer_control(&xfer->ep->desc) &&
+               done) {
+
+               dev_info(dev, "Control EP stall.  Queue delayed work.\n");
+               spin_lock(&wa->xfer_list_lock);
+               /* move xfer from xfer_list to xfer_errored_list. */
+               list_move_tail(&xfer->list_node, &wa->xfer_errored_list);
+               spin_unlock(&wa->xfer_list_lock);
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               queue_work(wusbd, &wa->xfer_error_work);
+       } else {
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               if (done)
+                       wa_xfer_completion(xfer);
+               if (rpipe_ready)
+                       wa_xfer_delayed_run(rpipe);
+       }
+
+       return;
+
+error_bad_seg:
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       wa_urb_dequeue(wa, xfer->urb, -ENOENT);
+       if (printk_ratelimit())
+               dev_err(dev, "xfer %p#%u: bad segment\n", xfer, seg_idx);
+       if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+               dev_err(dev, "DTI: URB max acceptable errors "
+                       "exceeded, resetting device\n");
+               wa_reset_all(wa);
+       }
+       return;
+
+segment_aborted:
+       /* nothing to do, as the aborter did the completion */
+       spin_unlock_irqrestore(&xfer->lock, flags);
+}
+
+/*
+ * Process a isochronous packet status message
+ *
+ * inbound transfers: need to schedule a buf_in_urb read
+ */
+static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb)
+{
+       struct device *dev = &wa->usb_iface->dev;
+       struct wa_xfer_packet_status_hwaiso *packet_status;
+       struct wa_xfer_packet_status_len_hwaiso *status_array;
+       struct wa_xfer *xfer;
+       unsigned long flags;
+       struct wa_seg *seg;
+       struct wa_rpipe *rpipe;
+       unsigned done = 0, dti_busy = 0, data_frame_count = 0, seg_index;
+       unsigned first_frame_index = 0, rpipe_ready = 0;
+       size_t expected_size;
+
+       /* We have a xfer result buffer; check it */
+       dev_dbg(dev, "DTI: isoc packet status %d bytes at %p\n",
+               urb->actual_length, urb->transfer_buffer);
+       packet_status = (struct wa_xfer_packet_status_hwaiso *)(wa->dti_buf);
+       if (packet_status->bPacketType != WA_XFER_ISO_PACKET_STATUS) {
+               dev_err(dev, "DTI Error: isoc packet status--bad type 0x%02x\n",
+                       packet_status->bPacketType);
+               goto error_parse_buffer;
+       }
+       xfer = wa_xfer_get_by_id(wa, wa->dti_isoc_xfer_in_progress);
+       if (xfer == NULL) {
+               dev_err(dev, "DTI Error: isoc packet status--unknown xfer 0x%08x\n",
+                       wa->dti_isoc_xfer_in_progress);
+               goto error_parse_buffer;
+       }
+       spin_lock_irqsave(&xfer->lock, flags);
+       if (unlikely(wa->dti_isoc_xfer_seg >= xfer->segs))
+               goto error_bad_seg;
+       seg = xfer->seg[wa->dti_isoc_xfer_seg];
+       rpipe = xfer->ep->hcpriv;
+       expected_size = struct_size(packet_status, PacketStatus,
+                                   seg->isoc_frame_count);
+       if (urb->actual_length != expected_size) {
+               dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %zu needed)\n",
+                       urb->actual_length, expected_size);
+               goto error_bad_seg;
+       }
+       if (le16_to_cpu(packet_status->wLength) != expected_size) {
+               dev_err(dev, "DTI Error: isoc packet status--bad length %u\n",
+                       le16_to_cpu(packet_status->wLength));
+               goto error_bad_seg;
+       }
+       /* write isoc packet status and lengths back to the xfer urb. */
+       status_array = packet_status->PacketStatus;
+       xfer->urb->start_frame =
+               wa->wusb->usb_hcd.driver->get_frame_number(&wa->wusb->usb_hcd);
+       for (seg_index = 0; seg_index < seg->isoc_frame_count; ++seg_index) {
+               struct usb_iso_packet_descriptor *iso_frame_desc =
+                       xfer->urb->iso_frame_desc;
+               const int xfer_frame_index =
+                       seg->isoc_frame_offset + seg_index;
+
+               iso_frame_desc[xfer_frame_index].status =
+                       wa_xfer_status_to_errno(
+                       le16_to_cpu(status_array[seg_index].PacketStatus));
+               iso_frame_desc[xfer_frame_index].actual_length =
+                       le16_to_cpu(status_array[seg_index].PacketLength);
+               /* track the number of frames successfully transferred. */
+               if (iso_frame_desc[xfer_frame_index].actual_length > 0) {
+                       /* save the starting frame index for buf_in_urb. */
+                       if (!data_frame_count)
+                               first_frame_index = seg_index;
+                       ++data_frame_count;
+               }
+       }
+
+       if (xfer->is_inbound && data_frame_count) {
+               int result, total_frames_read = 0, urb_index = 0;
+               struct urb *buf_in_urb;
+
+               /* IN data phase: read to buffer */
+               seg->status = WA_SEG_DTI_PENDING;
+
+               /* start with the first frame with data. */
+               seg->isoc_frame_index = first_frame_index;
+               /* submit up to WA_MAX_BUF_IN_URBS read URBs. */
+               do {
+                       int urb_frame_index, urb_frame_count;
+                       struct usb_iso_packet_descriptor *iso_frame_desc;
+
+                       buf_in_urb = &(wa->buf_in_urbs[urb_index]);
+                       urb_frame_count = __wa_populate_buf_in_urb_isoc(wa,
+                               buf_in_urb, xfer, seg);
+                       /* advance frame index to start of next read URB. */
+                       seg->isoc_frame_index += urb_frame_count;
+                       total_frames_read += urb_frame_count;
+
+                       ++(wa->active_buf_in_urbs);
+                       result = usb_submit_urb(buf_in_urb, GFP_ATOMIC);
+
+                       /* skip 0-byte frames. */
+                       urb_frame_index =
+                               seg->isoc_frame_offset + seg->isoc_frame_index;
+                       iso_frame_desc =
+                               &(xfer->urb->iso_frame_desc[urb_frame_index]);
+                       while ((seg->isoc_frame_index <
+                                               seg->isoc_frame_count) &&
+                                (iso_frame_desc->actual_length == 0)) {
+                               ++(seg->isoc_frame_index);
+                               ++iso_frame_desc;
+                       }
+                       ++urb_index;
+
+               } while ((result == 0) && (urb_index < WA_MAX_BUF_IN_URBS)
+                               && (seg->isoc_frame_index <
+                                               seg->isoc_frame_count));
+
+               if (result < 0) {
+                       --(wa->active_buf_in_urbs);
+                       dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
+                               result);
+                       wa_reset_all(wa);
+               } else if (data_frame_count > total_frames_read)
+                       /* If we need to read more frames, set DTI busy. */
+                       dti_busy = 1;
+       } else {
+               /* OUT transfer or no more IN data, complete it -- */
+               rpipe_ready = rpipe_avail_inc(rpipe);
+               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);
+       }
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       if (dti_busy)
+               wa->dti_state = WA_DTI_BUF_IN_DATA_PENDING;
+       else
+               wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
+       if (done)
+               wa_xfer_completion(xfer);
+       if (rpipe_ready)
+               wa_xfer_delayed_run(rpipe);
+       wa_xfer_put(xfer);
+       return dti_busy;
+
+error_bad_seg:
+       spin_unlock_irqrestore(&xfer->lock, flags);
+       wa_xfer_put(xfer);
+error_parse_buffer:
+       return dti_busy;
+}
+
+/*
+ * Callback for the IN data phase
+ *
+ * If successful transition state; otherwise, take a note of the
+ * error, mark this segment done and try completion.
+ *
+ * Note we don't access until we are sure that the transfer hasn't
+ * been cancelled (ECONNRESET, ENOENT), which could mean that
+ * seg->xfer could be already gone.
+ */
+static void wa_buf_in_cb(struct urb *urb)
+{
+       struct wa_seg *seg = urb->context;
+       struct wa_xfer *xfer = seg->xfer;
+       struct wahc *wa;
+       struct device *dev;
+       struct wa_rpipe *rpipe;
+       unsigned rpipe_ready = 0, isoc_data_frame_count = 0;
+       unsigned long flags;
+       int resubmit_dti = 0, active_buf_in_urbs;
+       u8 done = 0;
+
+       /* free the sg if it was used. */
+       kfree(urb->sg);
+       urb->sg = NULL;
+
+       spin_lock_irqsave(&xfer->lock, flags);
+       wa = xfer->wa;
+       dev = &wa->usb_iface->dev;
+       --(wa->active_buf_in_urbs);
+       active_buf_in_urbs = wa->active_buf_in_urbs;
+       rpipe = xfer->ep->hcpriv;
+
+       if (usb_pipeisoc(xfer->urb->pipe)) {
+               struct usb_iso_packet_descriptor *iso_frame_desc =
+                       xfer->urb->iso_frame_desc;
+               int     seg_index;
+
+               /*
+                * Find the next isoc frame with data and count how many
+                * frames with data remain.
+                */
+               seg_index = seg->isoc_frame_index;
+               while (seg_index < seg->isoc_frame_count) {
+                       const int urb_frame_index =
+                               seg->isoc_frame_offset + seg_index;
+
+                       if (iso_frame_desc[urb_frame_index].actual_length > 0) {
+                               /* save the index of the next frame with data */
+                               if (!isoc_data_frame_count)
+                                       seg->isoc_frame_index = seg_index;
+                               ++isoc_data_frame_count;
+                       }
+                       ++seg_index;
+               }
+       }
+       spin_unlock_irqrestore(&xfer->lock, flags);
+
+       switch (urb->status) {
+       case 0:
+               spin_lock_irqsave(&xfer->lock, flags);
+
+               seg->result += urb->actual_length;
+               if (isoc_data_frame_count > 0) {
+                       int result, urb_frame_count;
+
+                       /* submit a read URB for the next frame with data. */
+                       urb_frame_count = __wa_populate_buf_in_urb_isoc(wa, urb,
+                                xfer, seg);
+                       /* advance index to start of next read URB. */
+                       seg->isoc_frame_index += urb_frame_count;
+                       ++(wa->active_buf_in_urbs);
+                       result = usb_submit_urb(urb, GFP_ATOMIC);
+                       if (result < 0) {
+                               --(wa->active_buf_in_urbs);
+                               dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
+                                       result);
+                               wa_reset_all(wa);
+                       }
+                       /*
+                        * If we are in this callback and
+                        * isoc_data_frame_count > 0, it means that the dti_urb
+                        * submission was delayed in wa_dti_cb.  Once
+                        * we submit the last buf_in_urb, we can submit the
+                        * delayed dti_urb.
+                        */
+                         resubmit_dti = (isoc_data_frame_count ==
+                                                       urb_frame_count);
+               } else if (active_buf_in_urbs == 0) {
+                       dev_dbg(dev,
+                               "xfer %p 0x%08X#%u: data in done (%zu bytes)\n",
+                               xfer, wa_xfer_id(xfer), seg->index,
+                               seg->result);
+                       rpipe_ready = rpipe_avail_inc(rpipe);
+                       done = __wa_xfer_mark_seg_as_done(xfer, seg,
+                                       WA_SEG_DONE);
+               }
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               if (done)
+                       wa_xfer_completion(xfer);
+               if (rpipe_ready)
+                       wa_xfer_delayed_run(rpipe);
+               break;
+       case -ECONNRESET:       /* URB unlinked; no need to do anything */
+       case -ENOENT:           /* as it was done by the who unlinked us */
+               break;
+       default:                /* Other errors ... */
+               /*
+                * Error on data buf read.  Only resubmit DTI if it hasn't
+                * already been done by previously hitting this error or by a
+                * successful completion of the previous buf_in_urb.
+                */
+               resubmit_dti = wa->dti_state != WA_DTI_TRANSFER_RESULT_PENDING;
+               spin_lock_irqsave(&xfer->lock, flags);
+               if (printk_ratelimit())
+                       dev_err(dev, "xfer %p 0x%08X#%u: data in error %d\n",
+                               xfer, wa_xfer_id(xfer), seg->index,
+                               urb->status);
+               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
+                           EDC_ERROR_TIMEFRAME)){
+                       dev_err(dev, "DTO: URB max acceptable errors "
+                               "exceeded, resetting device\n");
+                       wa_reset_all(wa);
+               }
+               seg->result = urb->status;
+               rpipe_ready = rpipe_avail_inc(rpipe);
+               if (active_buf_in_urbs == 0)
+                       done = __wa_xfer_mark_seg_as_done(xfer, seg,
+                               WA_SEG_ERROR);
+               else
+                       __wa_xfer_abort(xfer);
+               spin_unlock_irqrestore(&xfer->lock, flags);
+               if (done)
+                       wa_xfer_completion(xfer);
+               if (rpipe_ready)
+                       wa_xfer_delayed_run(rpipe);
+       }
+
+       if (resubmit_dti) {
+               int result;
+
+               wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
+
+               result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
+               if (result < 0) {
+                       dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n",
+                               result);
+                       wa_reset_all(wa);
+               }
+       }
+}
+
+/*
+ * Handle an incoming transfer result buffer
+ *
+ * Given a transfer result buffer, it completes the transfer (possibly
+ * scheduling and buffer in read) and then resubmits the DTI URB for a
+ * new transfer result read.
+ *
+ *
+ * The xfer_result DTI URB state machine
+ *
+ * States: OFF | RXR (Read-Xfer-Result) | RBI (Read-Buffer-In)
+ *
+ * We start in OFF mode, the first xfer_result notification [through
+ * wa_handle_notif_xfer()] moves us to RXR by posting the DTI-URB to
+ * read.
+ *
+ * We receive a buffer -- if it is not a xfer_result, we complain and
+ * repost the DTI-URB. If it is a xfer_result then do the xfer seg
+ * request accounting. If it is an IN segment, we move to RBI and post
+ * a BUF-IN-URB to the right buffer. The BUF-IN-URB callback will
+ * repost the DTI-URB and move to RXR state. if there was no IN
+ * segment, it will repost the DTI-URB.
+ *
+ * We go back to OFF when we detect a ENOENT or ESHUTDOWN (or too many
+ * errors) in the URBs.
+ */
+static void wa_dti_cb(struct urb *urb)
+{
+       int result, dti_busy = 0;
+       struct wahc *wa = urb->context;
+       struct device *dev = &wa->usb_iface->dev;
+       u32 xfer_id;
+       u8 usb_status;
+
+       BUG_ON(wa->dti_urb != urb);
+       switch (wa->dti_urb->status) {
+       case 0:
+               if (wa->dti_state == WA_DTI_TRANSFER_RESULT_PENDING) {
+                       struct wa_xfer_result *xfer_result;
+                       struct wa_xfer *xfer;
+
+                       /* We have a xfer result buffer; check it */
+                       dev_dbg(dev, "DTI: xfer result %d bytes at %p\n",
+                               urb->actual_length, urb->transfer_buffer);
+                       if (urb->actual_length != sizeof(*xfer_result)) {
+                               dev_err(dev, "DTI Error: xfer result--bad size xfer result (%d bytes vs %zu needed)\n",
+                                       urb->actual_length,
+                                       sizeof(*xfer_result));
+                               break;
+                       }
+                       xfer_result = (struct wa_xfer_result *)(wa->dti_buf);
+                       if (xfer_result->hdr.bLength != sizeof(*xfer_result)) {
+                               dev_err(dev, "DTI Error: xfer result--bad header length %u\n",
+                                       xfer_result->hdr.bLength);
+                               break;
+                       }
+                       if (xfer_result->hdr.bNotifyType != WA_XFER_RESULT) {
+                               dev_err(dev, "DTI Error: xfer result--bad header type 0x%02x\n",
+                                       xfer_result->hdr.bNotifyType);
+                               break;
+                       }
+                       xfer_id = le32_to_cpu(xfer_result->dwTransferID);
+                       usb_status = xfer_result->bTransferStatus & 0x3f;
+                       if (usb_status == WA_XFER_STATUS_NOT_FOUND) {
+                               /* taken care of already */
+                               dev_dbg(dev, "%s: xfer 0x%08X#%u not found.\n",
+                                       __func__, xfer_id,
+                                       xfer_result->bTransferSegment & 0x7f);
+                               break;
+                       }
+                       xfer = wa_xfer_get_by_id(wa, xfer_id);
+                       if (xfer == NULL) {
+                               /* FIXME: transaction not found. */
+                               dev_err(dev, "DTI Error: xfer result--unknown xfer 0x%08x (status 0x%02x)\n",
+                                       xfer_id, usb_status);
+                               break;
+                       }
+                       wa_xfer_result_chew(wa, xfer, xfer_result);
+                       wa_xfer_put(xfer);
+               } else if (wa->dti_state == WA_DTI_ISOC_PACKET_STATUS_PENDING) {
+                       dti_busy = wa_process_iso_packet_status(wa, urb);
+               } else {
+                       dev_err(dev, "DTI Error: unexpected EP state = %d\n",
+                               wa->dti_state);
+               }
+               break;
+       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
+       case -ESHUTDOWN:        /* going away! */
+               dev_dbg(dev, "DTI: going down! %d\n", urb->status);
+               goto out;
+       default:
+               /* Unknown error */
+               if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS,
+                           EDC_ERROR_TIMEFRAME)) {
+                       dev_err(dev, "DTI: URB max acceptable errors "
+                               "exceeded, resetting device\n");
+                       wa_reset_all(wa);
+                       goto out;
+               }
+               if (printk_ratelimit())
+                       dev_err(dev, "DTI: URB error %d\n", urb->status);
+               break;
+       }
+
+       /* Resubmit the DTI URB if we are not busy processing isoc in frames. */
+       if (!dti_busy) {
+               result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
+               if (result < 0) {
+                       dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n",
+                               result);
+                       wa_reset_all(wa);
+               }
+       }
+out:
+       return;
+}
+
+/*
+ * Initialize the DTI URB for reading transfer result notifications and also
+ * the buffer-in URB, for reading buffers. Then we just submit the DTI URB.
+ */
+int wa_dti_start(struct wahc *wa)
+{
+       const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
+       struct device *dev = &wa->usb_iface->dev;
+       int result = -ENOMEM, index;
+
+       if (wa->dti_urb != NULL)        /* DTI URB already started */
+               goto out;
+
+       wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (wa->dti_urb == NULL)
+               goto error_dti_urb_alloc;
+       usb_fill_bulk_urb(
+               wa->dti_urb, wa->usb_dev,
+               usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress),
+               wa->dti_buf, wa->dti_buf_size,
+               wa_dti_cb, wa);
+
+       /* init the buf in URBs */
+       for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index) {
+               usb_fill_bulk_urb(
+                       &(wa->buf_in_urbs[index]), wa->usb_dev,
+                       usb_rcvbulkpipe(wa->usb_dev,
+                               0x80 | dti_epd->bEndpointAddress),
+                       NULL, 0, wa_buf_in_cb, wa);
+       }
+       result = usb_submit_urb(wa->dti_urb, GFP_KERNEL);
+       if (result < 0) {
+               dev_err(dev, "DTI Error: Could not submit DTI URB (%d) resetting\n",
+                       result);
+               goto error_dti_urb_submit;
+       }
+out:
+       return 0;
+
+error_dti_urb_submit:
+       usb_put_urb(wa->dti_urb);
+       wa->dti_urb = NULL;
+error_dti_urb_alloc:
+       return result;
+}
+EXPORT_SYMBOL_GPL(wa_dti_start);
+/*
+ * Transfer complete notification
+ *
+ * Called from the notif.c code. We get a notification on EP2 saying
+ * that some endpoint has some transfer result data available. We are
+ * about to read it.
+ *
+ * To speed up things, we always have a URB reading the DTI URB; we
+ * don't really set it up and start it until the first xfer complete
+ * notification arrives, which is what we do here.
+ *
+ * Follow up in wa_dti_cb(), as that's where the whole state
+ * machine starts.
+ *
+ * @wa shall be referenced
+ */
+void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
+{
+       struct device *dev = &wa->usb_iface->dev;
+       struct wa_notif_xfer *notif_xfer;
+       const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
+
+       notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr);
+       BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER);
+
+       if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) {
+               /* FIXME: hardcoded limitation, adapt */
+               dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n",
+                       notif_xfer->bEndpoint, dti_epd->bEndpointAddress);
+               goto error;
+       }
+
+       /* attempt to start the DTI ep processing. */
+       if (wa_dti_start(wa) < 0)
+               goto error;
+
+       return;
+
+error:
+       wa_reset_all(wa);
+}
diff --git a/drivers/staging/wusbcore/wusbhc.c b/drivers/staging/wusbcore/wusbhc.c
new file mode 100644 (file)
index 0000000..d0b404d
--- /dev/null
@@ -0,0 +1,490 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Host Controller
+ * sysfs glue, wusbcore module support and life cycle management
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * Creation/destruction of wusbhc is split in two parts; that that
+ * doesn't require the HCD to be added (wusbhc_{create,destroy}) and
+ * the one that requires (phase B, wusbhc_b_{create,destroy}).
+ *
+ * This is so because usb_add_hcd() will start the HC, and thus, all
+ * the HC specific stuff has to be already initialized (like sysfs
+ * thingies).
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include "wusbhc.h"
+
+/**
+ * Extract the wusbhc that corresponds to a USB Host Controller class device
+ *
+ * WARNING! Apply only if @dev is that of a
+ *          wusbhc.usb_hcd.self->class_dev; otherwise, you loose.
+ */
+static struct wusbhc *usbhc_dev_to_wusbhc(struct device *dev)
+{
+       struct usb_bus *usb_bus = dev_get_drvdata(dev);
+       struct usb_hcd *usb_hcd = bus_to_hcd(usb_bus);
+       return usb_hcd_to_wusbhc(usb_hcd);
+}
+
+/*
+ * Show & store the current WUSB trust timeout
+ *
+ * We don't do locking--it is an 'atomic' value.
+ *
+ * The units that we store/show are always MILLISECONDS. However, the
+ * value of trust_timeout is jiffies.
+ */
+static ssize_t wusb_trust_timeout_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n", wusbhc->trust_timeout);
+}
+
+static ssize_t wusb_trust_timeout_store(struct device *dev,
+                                       struct device_attribute *attr,
+                                       const char *buf, size_t size)
+{
+       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+       ssize_t result = -ENOSYS;
+       unsigned trust_timeout;
+
+       result = sscanf(buf, "%u", &trust_timeout);
+       if (result != 1) {
+               result = -EINVAL;
+               goto out;
+       }
+       wusbhc->trust_timeout = min_t(unsigned, trust_timeout, 500);
+       cancel_delayed_work(&wusbhc->keep_alive_timer);
+       flush_workqueue(wusbd);
+       queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
+                          msecs_to_jiffies(wusbhc->trust_timeout / 2));
+out:
+       return result < 0 ? result : size;
+}
+static DEVICE_ATTR_RW(wusb_trust_timeout);
+
+/*
+ * Show the current WUSB CHID.
+ */
+static ssize_t wusb_chid_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+       const struct wusb_ckhdid *chid;
+
+       if (wusbhc->wuie_host_info != NULL)
+               chid = &wusbhc->wuie_host_info->CHID;
+       else
+               chid = &wusb_ckhdid_zero;
+
+       return sprintf(buf, "%16ph\n", chid->data);
+}
+
+/*
+ * Store a new CHID.
+ *
+ * - Write an all zeros CHID and it will stop the controller
+ * - Write a non-zero CHID and it will start it.
+ *
+ * See wusbhc_chid_set() for more info.
+ */
+static ssize_t wusb_chid_store(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf, size_t size)
+{
+       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+       struct wusb_ckhdid chid;
+       ssize_t result;
+
+       result = sscanf(buf,
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx "
+                       "%02hhx %02hhx %02hhx %02hhx\n",
+                       &chid.data[0] , &chid.data[1] ,
+                       &chid.data[2] , &chid.data[3] ,
+                       &chid.data[4] , &chid.data[5] ,
+                       &chid.data[6] , &chid.data[7] ,
+                       &chid.data[8] , &chid.data[9] ,
+                       &chid.data[10], &chid.data[11],
+                       &chid.data[12], &chid.data[13],
+                       &chid.data[14], &chid.data[15]);
+       if (result != 16) {
+               dev_err(dev, "Unrecognized CHID (need 16 8-bit hex digits): "
+                       "%d\n", (int)result);
+               return -EINVAL;
+       }
+       result = wusbhc_chid_set(wusbhc, &chid);
+       return result < 0 ? result : size;
+}
+static DEVICE_ATTR_RW(wusb_chid);
+
+
+static ssize_t wusb_phy_rate_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+       return sprintf(buf, "%d\n", wusbhc->phy_rate);
+}
+
+static ssize_t wusb_phy_rate_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t size)
+{
+       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+       uint8_t phy_rate;
+       ssize_t result;
+
+       result = sscanf(buf, "%hhu", &phy_rate);
+       if (result != 1)
+               return -EINVAL;
+       if (phy_rate >= UWB_PHY_RATE_INVALID)
+               return -EINVAL;
+
+       wusbhc->phy_rate = phy_rate;
+       return size;
+}
+static DEVICE_ATTR_RW(wusb_phy_rate);
+
+static ssize_t wusb_dnts_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+       return sprintf(buf, "num slots: %d\ninterval: %dms\n",
+                       wusbhc->dnts_num_slots, wusbhc->dnts_interval);
+}
+
+static ssize_t wusb_dnts_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t size)
+{
+       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+       uint8_t num_slots, interval;
+       ssize_t result;
+
+       result = sscanf(buf, "%hhu %hhu", &num_slots, &interval);
+
+       if (result != 2)
+               return -EINVAL;
+
+       wusbhc->dnts_num_slots = num_slots;
+       wusbhc->dnts_interval = interval;
+
+       return size;
+}
+static DEVICE_ATTR_RW(wusb_dnts);
+
+static ssize_t wusb_retry_count_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+
+       return sprintf(buf, "%d\n", wusbhc->retry_count);
+}
+
+static ssize_t wusb_retry_count_store(struct device *dev,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t size)
+{
+       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
+       uint8_t retry_count;
+       ssize_t result;
+
+       result = sscanf(buf, "%hhu", &retry_count);
+
+       if (result != 1)
+               return -EINVAL;
+
+       wusbhc->retry_count = max_t(uint8_t, retry_count,
+                                       WUSB_RETRY_COUNT_MAX);
+
+       return size;
+}
+static DEVICE_ATTR_RW(wusb_retry_count);
+
+/* Group all the WUSBHC attributes */
+static struct attribute *wusbhc_attrs[] = {
+               &dev_attr_wusb_trust_timeout.attr,
+               &dev_attr_wusb_chid.attr,
+               &dev_attr_wusb_phy_rate.attr,
+               &dev_attr_wusb_dnts.attr,
+               &dev_attr_wusb_retry_count.attr,
+               NULL,
+};
+
+static const struct attribute_group wusbhc_attr_group = {
+       .name = NULL,   /* we want them in the same directory */
+       .attrs = wusbhc_attrs,
+};
+
+/*
+ * Create a wusbhc instance
+ *
+ * NOTEs:
+ *
+ *  - assumes *wusbhc has been zeroed and wusbhc->usb_hcd has been
+ *    initialized but not added.
+ *
+ *  - fill out ports_max, mmcies_max and mmcie_{add,rm} before calling.
+ *
+ *  - fill out wusbhc->uwb_rc and refcount it before calling
+ *  - fill out the wusbhc->sec_modes array
+ */
+int wusbhc_create(struct wusbhc *wusbhc)
+{
+       int result = 0;
+
+       /* set defaults.  These can be overwritten using sysfs attributes. */
+       wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS;
+       wusbhc->phy_rate = UWB_PHY_RATE_INVALID - 1;
+       wusbhc->dnts_num_slots = 4;
+       wusbhc->dnts_interval = 2;
+       wusbhc->retry_count = WUSB_RETRY_COUNT_INFINITE;
+
+       mutex_init(&wusbhc->mutex);
+       result = wusbhc_mmcie_create(wusbhc);
+       if (result < 0)
+               goto error_mmcie_create;
+       result = wusbhc_devconnect_create(wusbhc);
+       if (result < 0)
+               goto error_devconnect_create;
+       result = wusbhc_rh_create(wusbhc);
+       if (result < 0)
+               goto error_rh_create;
+       result = wusbhc_sec_create(wusbhc);
+       if (result < 0)
+               goto error_sec_create;
+       return 0;
+
+error_sec_create:
+       wusbhc_rh_destroy(wusbhc);
+error_rh_create:
+       wusbhc_devconnect_destroy(wusbhc);
+error_devconnect_create:
+       wusbhc_mmcie_destroy(wusbhc);
+error_mmcie_create:
+       return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_create);
+
+static inline struct kobject *wusbhc_kobj(struct wusbhc *wusbhc)
+{
+       return &wusbhc->usb_hcd.self.controller->kobj;
+}
+
+/*
+ * Phase B of a wusbhc instance creation
+ *
+ * Creates fields that depend on wusbhc->usb_hcd having been
+ * added. This is where we create the sysfs files in
+ * /sys/class/usb_host/usb_hostX/.
+ *
+ * NOTE: Assumes wusbhc->usb_hcd has been already added by the upper
+ *       layer (hwahc or whci)
+ */
+int wusbhc_b_create(struct wusbhc *wusbhc)
+{
+       int result = 0;
+       struct device *dev = wusbhc->usb_hcd.self.controller;
+
+       result = sysfs_create_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
+       if (result < 0) {
+               dev_err(dev, "Cannot register WUSBHC attributes: %d\n",
+                       result);
+               goto error_create_attr_group;
+       }
+
+       return 0;
+error_create_attr_group:
+       return result;
+}
+EXPORT_SYMBOL_GPL(wusbhc_b_create);
+
+void wusbhc_b_destroy(struct wusbhc *wusbhc)
+{
+       wusbhc_pal_unregister(wusbhc);
+       sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
+}
+EXPORT_SYMBOL_GPL(wusbhc_b_destroy);
+
+void wusbhc_destroy(struct wusbhc *wusbhc)
+{
+       wusbhc_sec_destroy(wusbhc);
+       wusbhc_rh_destroy(wusbhc);
+       wusbhc_devconnect_destroy(wusbhc);
+       wusbhc_mmcie_destroy(wusbhc);
+}
+EXPORT_SYMBOL_GPL(wusbhc_destroy);
+
+struct workqueue_struct *wusbd;
+EXPORT_SYMBOL_GPL(wusbd);
+
+/*
+ * WUSB Cluster ID allocation map
+ *
+ * Each WUSB bus in a channel is identified with a Cluster Id in the
+ * unauth address pace (WUSB1.0[4.3]). We take the range 0xe0 to 0xff
+ * (that's space for 31 WUSB controllers, as 0xff can't be taken). We
+ * start taking from 0xff, 0xfe, 0xfd... (hence the += or -= 0xff).
+ *
+ * For each one we taken, we pin it in the bitap
+ */
+#define CLUSTER_IDS 32
+static DECLARE_BITMAP(wusb_cluster_id_table, CLUSTER_IDS);
+static DEFINE_SPINLOCK(wusb_cluster_ids_lock);
+
+/*
+ * Get a WUSB Cluster ID
+ *
+ * Need to release with wusb_cluster_id_put() when done w/ it.
+ */
+/* FIXME: coordinate with the choose_addres() from the USB stack */
+/* we want to leave the top of the 128 range for cluster addresses and
+ * the bottom for device addresses (as we map them one on one with
+ * ports). */
+u8 wusb_cluster_id_get(void)
+{
+       u8 id;
+       spin_lock(&wusb_cluster_ids_lock);
+       id = find_first_zero_bit(wusb_cluster_id_table, CLUSTER_IDS);
+       if (id >= CLUSTER_IDS) {
+               id = 0;
+               goto out;
+       }
+       set_bit(id, wusb_cluster_id_table);
+       id = (u8) 0xff - id;
+out:
+       spin_unlock(&wusb_cluster_ids_lock);
+       return id;
+
+}
+EXPORT_SYMBOL_GPL(wusb_cluster_id_get);
+
+/*
+ * Release a WUSB Cluster ID
+ *
+ * Obtained it with wusb_cluster_id_get()
+ */
+void wusb_cluster_id_put(u8 id)
+{
+       id = 0xff - id;
+       BUG_ON(id >= CLUSTER_IDS);
+       spin_lock(&wusb_cluster_ids_lock);
+       WARN_ON(!test_bit(id, wusb_cluster_id_table));
+       clear_bit(id, wusb_cluster_id_table);
+       spin_unlock(&wusb_cluster_ids_lock);
+}
+EXPORT_SYMBOL_GPL(wusb_cluster_id_put);
+
+/**
+ * wusbhc_giveback_urb - return an URB to the USB core
+ * @wusbhc: the host controller the URB is from.
+ * @urb:    the URB.
+ * @status: the URB's status.
+ *
+ * Return an URB to the USB core doing some additional WUSB specific
+ * processing.
+ *
+ *  - After a successful transfer, update the trust timeout timestamp
+ *    for the WUSB device.
+ *
+ *  - [WUSB] sections 4.13 and 7.5.1 specify the stop retransmission
+ *    condition for the WCONNECTACK_IE is that the host has observed
+ *    the associated device responding to a control transfer.
+ */
+void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status)
+{
+       struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc,
+                                       urb->dev);
+
+       if (status == 0 && wusb_dev) {
+               wusb_dev->entry_ts = jiffies;
+
+               /* wusbhc_devconnect_acked() can't be called from
+                  atomic context so defer it to a work queue. */
+               if (!list_empty(&wusb_dev->cack_node))
+                       queue_work(wusbd, &wusb_dev->devconnect_acked_work);
+               else
+                       wusb_dev_put(wusb_dev);
+       }
+
+       usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status);
+}
+EXPORT_SYMBOL_GPL(wusbhc_giveback_urb);
+
+/**
+ * wusbhc_reset_all - reset the HC hardware
+ * @wusbhc: the host controller to reset.
+ *
+ * Request a full hardware reset of the chip.  This will also reset
+ * the radio controller and any other PALs.
+ */
+void wusbhc_reset_all(struct wusbhc *wusbhc)
+{
+       if (wusbhc->uwb_rc)
+               uwb_rc_reset_all(wusbhc->uwb_rc);
+}
+EXPORT_SYMBOL_GPL(wusbhc_reset_all);
+
+static struct notifier_block wusb_usb_notifier = {
+       .notifier_call = wusb_usb_ncb,
+       .priority = INT_MAX     /* Need to be called first of all */
+};
+
+static int __init wusbcore_init(void)
+{
+       int result;
+       result = wusb_crypto_init();
+       if (result < 0)
+               goto error_crypto_init;
+       /* WQ is singlethread because we need to serialize notifications */
+       wusbd = create_singlethread_workqueue("wusbd");
+       if (wusbd == NULL) {
+               result = -ENOMEM;
+               printk(KERN_ERR "WUSB-core: Cannot create wusbd workqueue\n");
+               goto error_wusbd_create;
+       }
+       usb_register_notify(&wusb_usb_notifier);
+       bitmap_zero(wusb_cluster_id_table, CLUSTER_IDS);
+       set_bit(0, wusb_cluster_id_table);      /* reserve Cluster ID 0xff */
+       return 0;
+
+error_wusbd_create:
+       wusb_crypto_exit();
+error_crypto_init:
+       return result;
+
+}
+module_init(wusbcore_init);
+
+static void __exit wusbcore_exit(void)
+{
+       clear_bit(0, wusb_cluster_id_table);
+       if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) {
+               printk(KERN_ERR "BUG: WUSB Cluster IDs not released on exit: %*pb\n",
+                      CLUSTER_IDS, wusb_cluster_id_table);
+               WARN_ON(1);
+       }
+       usb_unregister_notify(&wusb_usb_notifier);
+       destroy_workqueue(wusbd);
+       wusb_crypto_exit();
+}
+module_exit(wusbcore_exit);
+
+MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
+MODULE_DESCRIPTION("Wireless USB core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/wusbcore/wusbhc.h b/drivers/staging/wusbcore/wusbhc.h
new file mode 100644 (file)
index 0000000..716244a
--- /dev/null
@@ -0,0 +1,487 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Wireless USB Host Controller
+ * Common infrastructure for WHCI and HWA WUSB-HC drivers
+ *
+ *
+ * Copyright (C) 2005-2006 Intel Corporation
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *
+ * This driver implements parts common to all Wireless USB Host
+ * Controllers (struct wusbhc, embedding a struct usb_hcd) and is used
+ * by:
+ *
+ *   - hwahc: HWA, USB-dongle that implements a Wireless USB host
+ *     controller, (Wireless USB 1.0 Host-Wire-Adapter specification).
+ *
+ *   - whci: WHCI, a PCI card with a wireless host controller
+ *     (Wireless Host Controller Interface 1.0 specification).
+ *
+ * Check out the Design-overview.txt file in the source documentation
+ * for other details on the implementation.
+ *
+ * Main blocks:
+ *
+ *  rh         Root Hub emulation (part of the HCD glue)
+ *
+ *  devconnect Handle all the issues related to device connection,
+ *             authentication, disconnection, timeout, reseting,
+ *             keepalives, etc.
+ *
+ *  mmc        MMC IE broadcasting handling
+ *
+ * A host controller driver just initializes its stuff and as part of
+ * that, creates a 'struct wusbhc' instance that handles all the
+ * common WUSB mechanisms. Links in the function ops that are specific
+ * to it and then registers the host controller. Ready to run.
+ */
+
+#ifndef __WUSBHC_H__
+#define __WUSBHC_H__
+
+#include <linux/usb.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/kref.h>
+#include <linux/workqueue.h>
+#include <linux/usb/hcd.h>
+#include "../uwb/uwb.h"
+#include "include/wusb.h"
+
+/*
+ * Time from a WUSB channel stop request to the last transmitted MMC.
+ *
+ * This needs to be > 4.096 ms in case no MMCs can be transmitted in
+ * zone 0.
+ */
+#define WUSB_CHANNEL_STOP_DELAY_MS 8
+#define WUSB_RETRY_COUNT_MAX 15
+#define WUSB_RETRY_COUNT_INFINITE 0
+
+/**
+ * Wireless USB device
+ *
+ * Describe a WUSB device connected to the cluster. This struct
+ * belongs to the 'struct wusb_port' it is attached to and it is
+ * responsible for putting and clearing the pointer to it.
+ *
+ * Note this "complements" the 'struct usb_device' that the usb_hcd
+ * keeps for each connected USB device. However, it extends some
+ * information that is not available (there is no hcpriv ptr in it!)
+ * *and* most importantly, it's life cycle is different. It is created
+ * as soon as we get a DN_Connect (connect request notification) from
+ * the device through the WUSB host controller; the USB stack doesn't
+ * create the device until we authenticate it. FIXME: this will
+ * change.
+ *
+ * @bos:    This is allocated when the BOS descriptors are read from
+ *          the device and freed upon the wusb_dev struct dying.
+ * @wusb_cap_descr: points into @bos, and has been verified to be size
+ *                  safe.
+ */
+struct wusb_dev {
+       struct kref refcnt;
+       struct wusbhc *wusbhc;
+       struct list_head cack_node;     /* Connect-Ack list */
+       struct list_head rekey_node;    /* GTK rekey list */
+       u8 port_idx;
+       u8 addr;
+       u8 beacon_type:4;
+       struct usb_encryption_descriptor ccm1_etd;
+       struct wusb_ckhdid cdid;
+       unsigned long entry_ts;
+       struct usb_bos_descriptor *bos;
+       struct usb_wireless_cap_descriptor *wusb_cap_descr;
+       struct uwb_mas_bm availability;
+       struct work_struct devconnect_acked_work;
+       struct usb_device *usb_dev;
+};
+
+#define WUSB_DEV_ADDR_UNAUTH 0x80
+
+static inline void wusb_dev_init(struct wusb_dev *wusb_dev)
+{
+       kref_init(&wusb_dev->refcnt);
+       /* no need to init the cack_node */
+}
+
+extern void wusb_dev_destroy(struct kref *_wusb_dev);
+
+static inline struct wusb_dev *wusb_dev_get(struct wusb_dev *wusb_dev)
+{
+       kref_get(&wusb_dev->refcnt);
+       return wusb_dev;
+}
+
+static inline void wusb_dev_put(struct wusb_dev *wusb_dev)
+{
+       kref_put(&wusb_dev->refcnt, wusb_dev_destroy);
+}
+
+/**
+ * Wireless USB Host Controller root hub "fake" ports
+ * (state and device information)
+ *
+ * Wireless USB is wireless, so there are no ports; but we
+ * fake'em. Each RC can connect a max of devices at the same time
+ * (given in the Wireless Adapter descriptor, bNumPorts or WHCI's
+ * caps), referred to in wusbhc->ports_max.
+ *
+ * See rh.c for more information.
+ *
+ * The @status and @change use the same bits as in USB2.0[11.24.2.7],
+ * so we don't have to do much when getting the port's status.
+ *
+ * WUSB1.0[7.1], USB2.0[11.24.2.7.1,fig 11-10],
+ * include/linux/usb_ch9.h (#define USB_PORT_STAT_*)
+ */
+struct wusb_port {
+       u16 status;
+       u16 change;
+       struct wusb_dev *wusb_dev;      /* connected device's info */
+       u32 ptk_tkid;
+};
+
+/**
+ * WUSB Host Controller specifics
+ *
+ * All fields that are common to all Wireless USB controller types
+ * (HWA and WHCI) are grouped here. Host Controller
+ * functions/operations that only deal with general Wireless USB HC
+ * issues use this data type to refer to the host.
+ *
+ * @usb_hcd       Instantiation of a USB host controller
+ *                 (initialized by upper layer [HWA=HC or WHCI].
+ *
+ * @dev                   Device that implements this; initialized by the
+ *                 upper layer (HWA-HC, WHCI...); this device should
+ *                 have a refcount.
+ *
+ * @trust_timeout  After this time without hearing for device
+ *                 activity, we consider the device gone and we have to
+ *                 re-authenticate.
+ *
+ *                 Can be accessed w/o locking--however, read to a
+ *                 local variable then use.
+ *
+ * @chid           WUSB Cluster Host ID: this is supposed to be a
+ *                 unique value that doesn't change across reboots (so
+ *                 that your devices do not require re-association).
+ *
+ *                 Read/Write protected by @mutex
+ *
+ * @dev_info       This array has ports_max elements. It is used to
+ *                 give the HC information about the WUSB devices (see
+ *                 'struct wusb_dev_info').
+ *
+ *                For HWA we need to allocate it in heap; for WHCI it
+ *                 needs to be permanently mapped, so we keep it for
+ *                 both and make it easy. Call wusbhc->dev_info_set()
+ *                 to update an entry.
+ *
+ * @ports_max     Number of simultaneous device connections (fake
+ *                 ports) this HC will take. Read-only.
+ *
+ * @port          Array of port status for each fake root port. Guaranteed to
+ *                 always be the same length during device existence
+ *                 [this allows for some unlocked but referenced reading].
+ *
+ * @mmcies_max    Max number of Information Elements this HC can send
+ *                 in its MMC. Read-only.
+ *
+ * @start          Start the WUSB channel.
+ *
+ * @stop           Stop the WUSB channel after the specified number of
+ *                 milliseconds.  Channel Stop IEs should be transmitted
+ *                 as required by [WUSB] 4.16.2.1.
+ *
+ * @mmcie_add     HC specific operation (WHCI or HWA) for adding an
+ *                 MMCIE.
+ *
+ * @mmcie_rm      HC specific operation (WHCI or HWA) for removing an
+ *                 MMCIE.
+ *
+ * @set_ptk:       Set the PTK and enable encryption for a device. Or, if
+ *                 the supplied key is NULL, disable encryption for that
+ *                 device.
+ *
+ * @set_gtk:       Set the GTK to be used for all future broadcast packets
+ *                 (i.e., MMCs).  With some hardware, setting the GTK may start
+ *                 MMC transmission.
+ *
+ * NOTE:
+ *
+ *  - If wusb_dev->usb_dev is not NULL, then usb_dev is valid
+ *    (wusb_dev has a refcount on it). Likewise, if usb_dev->wusb_dev
+ *    is not NULL, usb_dev->wusb_dev is valid (usb_dev keeps a
+ *    refcount on it).
+ *
+ *    Most of the times when you need to use it, it will be non-NULL,
+ *    so there is no real need to check for it (wusb_dev will
+ *    disappear before usb_dev).
+ *
+ *  - The following fields need to be filled out before calling
+ *    wusbhc_create(): ports_max, mmcies_max, mmcie_{add,rm}.
+ *
+ *  - there is no wusbhc_init() method, we do everything in
+ *    wusbhc_create().
+ *
+ *  - Creation is done in two phases, wusbhc_create() and
+ *    wusbhc_create_b(); b are the parts that need to be called after
+ *    calling usb_hcd_add(&wusbhc->usb_hcd).
+ */
+struct wusbhc {
+       struct usb_hcd usb_hcd;         /* HAS TO BE 1st */
+       struct device *dev;
+       struct uwb_rc *uwb_rc;
+       struct uwb_pal pal;
+
+       unsigned trust_timeout;                 /* in jiffies */
+       struct wusb_ckhdid chid;
+       uint8_t phy_rate;
+       uint8_t dnts_num_slots;
+       uint8_t dnts_interval;
+       uint8_t retry_count;
+       struct wuie_host_info *wuie_host_info;
+
+       struct mutex mutex;                     /* locks everything else */
+       u16 cluster_id;                         /* Wireless USB Cluster ID */
+       struct wusb_port *port;                 /* Fake port status handling */
+       struct wusb_dev_info *dev_info;         /* for Set Device Info mgmt */
+       u8 ports_max;
+       unsigned active:1;                      /* currently xmit'ing MMCs */
+       struct wuie_keep_alive keep_alive_ie;   /* protected by mutex */
+       struct delayed_work keep_alive_timer;
+       struct list_head cack_list;             /* Connect acknowledging */
+       size_t cack_count;                      /* protected by 'mutex' */
+       struct wuie_connect_ack cack_ie;
+       struct uwb_rsv *rsv;            /* cluster bandwidth reservation */
+
+       struct mutex mmcie_mutex;               /* MMC WUIE handling */
+       struct wuie_hdr **mmcie;                /* WUIE array */
+       u8 mmcies_max;
+       /* FIXME: make wusbhc_ops? */
+       int (*start)(struct wusbhc *wusbhc);
+       void (*stop)(struct wusbhc *wusbhc, int delay);
+       int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
+                        u8 handle, struct wuie_hdr *wuie);
+       int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle);
+       int (*dev_info_set)(struct wusbhc *, struct wusb_dev *wusb_dev);
+       int (*bwa_set)(struct wusbhc *wusbhc, s8 stream_index,
+                      const struct uwb_mas_bm *);
+       int (*set_ptk)(struct wusbhc *wusbhc, u8 port_idx,
+                      u32 tkid, const void *key, size_t key_size);
+       int (*set_gtk)(struct wusbhc *wusbhc,
+                      u32 tkid, const void *key, size_t key_size);
+       int (*set_num_dnts)(struct wusbhc *wusbhc, u8 interval, u8 slots);
+
+       struct {
+               struct usb_key_descriptor descr;
+               u8 data[16];                            /* GTK key data */
+       } __attribute__((packed)) gtk;
+       u8 gtk_index;
+       u32 gtk_tkid;
+
+       /* workqueue for WUSB security related tasks. */
+       struct workqueue_struct *wq_security;
+       struct work_struct gtk_rekey_work;
+
+       struct usb_encryption_descriptor *ccm1_etd;
+};
+
+#define usb_hcd_to_wusbhc(u) container_of((u), struct wusbhc, usb_hcd)
+
+
+extern int wusbhc_create(struct wusbhc *);
+extern int wusbhc_b_create(struct wusbhc *);
+extern void wusbhc_b_destroy(struct wusbhc *);
+extern void wusbhc_destroy(struct wusbhc *);
+extern int wusb_dev_sysfs_add(struct wusbhc *, struct usb_device *,
+                             struct wusb_dev *);
+extern void wusb_dev_sysfs_rm(struct wusb_dev *);
+extern int wusbhc_sec_create(struct wusbhc *);
+extern int wusbhc_sec_start(struct wusbhc *);
+extern void wusbhc_sec_stop(struct wusbhc *);
+extern void wusbhc_sec_destroy(struct wusbhc *);
+extern void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb,
+                               int status);
+void wusbhc_reset_all(struct wusbhc *wusbhc);
+
+int wusbhc_pal_register(struct wusbhc *wusbhc);
+void wusbhc_pal_unregister(struct wusbhc *wusbhc);
+
+/*
+ * Return @usb_dev's @usb_hcd (properly referenced) or NULL if gone
+ *
+ * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr)
+ *
+ * This is a safe assumption as @usb_dev->bus is referenced all the
+ * time during the @usb_dev life cycle.
+ */
+static inline
+struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev)
+{
+       struct usb_hcd *usb_hcd;
+       usb_hcd = bus_to_hcd(usb_dev->bus);
+       return usb_get_hcd(usb_hcd);
+}
+
+/*
+ * Increment the reference count on a wusbhc.
+ *
+ * @wusbhc's life cycle is identical to that of the underlying usb_hcd.
+ */
+static inline struct wusbhc *wusbhc_get(struct wusbhc *wusbhc)
+{
+       return usb_get_hcd(&wusbhc->usb_hcd) ? wusbhc : NULL;
+}
+
+/*
+ * Return the wusbhc associated to a @usb_dev
+ *
+ * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr)
+ *
+ * @returns: wusbhc for @usb_dev; NULL if the @usb_dev is being torn down.
+ *           WARNING: referenced at the usb_hcd level, unlocked
+ *
+ * FIXME: move offline
+ */
+static inline struct wusbhc *wusbhc_get_by_usb_dev(struct usb_device *usb_dev)
+{
+       struct wusbhc *wusbhc = NULL;
+       struct usb_hcd *usb_hcd;
+       if (usb_dev->devnum > 1 && !usb_dev->wusb) {
+               /* but root hubs */
+               dev_err(&usb_dev->dev, "devnum %d wusb %d\n", usb_dev->devnum,
+                       usb_dev->wusb);
+               BUG_ON(usb_dev->devnum > 1 && !usb_dev->wusb);
+       }
+       usb_hcd = usb_hcd_get_by_usb_dev(usb_dev);
+       if (usb_hcd == NULL)
+               return NULL;
+       BUG_ON(usb_hcd->wireless == 0);
+       return wusbhc = usb_hcd_to_wusbhc(usb_hcd);
+}
+
+
+static inline void wusbhc_put(struct wusbhc *wusbhc)
+{
+       usb_put_hcd(&wusbhc->usb_hcd);
+}
+
+int wusbhc_start(struct wusbhc *wusbhc);
+void wusbhc_stop(struct wusbhc *wusbhc);
+extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *);
+
+/* Device connect handling */
+extern int wusbhc_devconnect_create(struct wusbhc *);
+extern void wusbhc_devconnect_destroy(struct wusbhc *);
+extern int wusbhc_devconnect_start(struct wusbhc *wusbhc);
+extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc);
+extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr,
+                            struct wusb_dn_hdr *dn_hdr, size_t size);
+extern void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port);
+extern int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,
+                       void *priv);
+extern int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
+                            u8 addr);
+
+/* Wireless USB fake Root Hub methods */
+extern int wusbhc_rh_create(struct wusbhc *);
+extern void wusbhc_rh_destroy(struct wusbhc *);
+
+extern int wusbhc_rh_status_data(struct usb_hcd *, char *);
+extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16);
+extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned);
+
+/* MMC handling */
+extern int wusbhc_mmcie_create(struct wusbhc *);
+extern void wusbhc_mmcie_destroy(struct wusbhc *);
+extern int wusbhc_mmcie_set(struct wusbhc *, u8 interval, u8 repeat_cnt,
+                           struct wuie_hdr *);
+extern void wusbhc_mmcie_rm(struct wusbhc *, struct wuie_hdr *);
+
+/* Bandwidth reservation */
+int wusbhc_rsv_establish(struct wusbhc *wusbhc);
+void wusbhc_rsv_terminate(struct wusbhc *wusbhc);
+
+/*
+ * I've always said
+ * I wanted a wedding in a church...
+ *
+ * but lately I've been thinking about
+ * the Botanical Gardens.
+ *
+ * We could do it by the tulips.
+ * It'll be beautiful
+ *
+ * --Security!
+ */
+extern int wusb_dev_sec_add(struct wusbhc *, struct usb_device *,
+                               struct wusb_dev *);
+extern void wusb_dev_sec_rm(struct wusb_dev *) ;
+extern int wusb_dev_4way_handshake(struct wusbhc *, struct wusb_dev *,
+                                  struct wusb_ckhdid *ck);
+void wusbhc_gtk_rekey(struct wusbhc *wusbhc);
+int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
+
+
+/* WUSB Cluster ID handling */
+extern u8 wusb_cluster_id_get(void);
+extern void wusb_cluster_id_put(u8);
+
+/*
+ * wusb_port_by_idx - return the port associated to a zero-based port index
+ *
+ * NOTE: valid without locking as long as wusbhc is referenced (as the
+ *       number of ports doesn't change). The data pointed to has to
+ *       be verified though :)
+ */
+static inline struct wusb_port *wusb_port_by_idx(struct wusbhc *wusbhc,
+                                                u8 port_idx)
+{
+       return &wusbhc->port[port_idx];
+}
+
+/*
+ * wusb_port_no_to_idx - Convert port number (per usb_dev->portnum) to
+ * a port_idx.
+ *
+ * USB stack USB ports are 1 based!!
+ *
+ * NOTE: only valid for WUSB devices!!!
+ */
+static inline u8 wusb_port_no_to_idx(u8 port_no)
+{
+       return port_no - 1;
+}
+
+extern struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *,
+                                                 struct usb_device *);
+
+/*
+ * Return a referenced wusb_dev given a @usb_dev
+ *
+ * Returns NULL if the usb_dev is being torn down.
+ *
+ * FIXME: move offline
+ */
+static inline
+struct wusb_dev *wusb_dev_get_by_usb_dev(struct usb_device *usb_dev)
+{
+       struct wusbhc *wusbhc;
+       struct wusb_dev *wusb_dev;
+       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
+       if (wusbhc == NULL)
+               return NULL;
+       mutex_lock(&wusbhc->mutex);
+       wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev);
+       mutex_unlock(&wusbhc->mutex);
+       wusbhc_put(wusbhc);
+       return wusb_dev;
+}
+
+/* Misc */
+
+extern struct workqueue_struct *wusbd;
+#endif /* #ifndef __WUSBHC_H__ */
index 6e59d370ef8104bd25794305146be6878219d6d2..9987c399819f7a1b4e40feb61c04a31c65fc50c4 100644 (file)
@@ -98,8 +98,6 @@ source "drivers/usb/core/Kconfig"
 
 source "drivers/usb/mon/Kconfig"
 
-source "drivers/usb/wusbcore/Kconfig"
-
 source "drivers/usb/host/Kconfig"
 
 source "drivers/usb/renesas_usbhs/Kconfig"
index ecc2de1ffaaeab7b2c59bf902a08c396cd4882b5..db064dd59e089e8050832a95c1dcc58f4e518659 100644 (file)
@@ -35,8 +35,6 @@ obj-$(CONFIG_USB_MAX3421_HCD) += host/
 
 obj-$(CONFIG_USB_C67X00_HCD)   += c67x00/
 
-obj-$(CONFIG_USB_WUSB)         += wusbcore/
-
 obj-$(CONFIG_USB_ACM)          += class/
 obj-$(CONFIG_USB_PRINTER)      += class/
 obj-$(CONFIG_USB_WDM)          += class/
index 40b5de59711299b608f45523f5798bbba135919b..d040408f5baaff306458d4182eef66ca35f639ef 100644 (file)
@@ -717,32 +717,6 @@ config USB_RENESAS_USBHS_HCD
          To compile this driver as a module, choose M here: the
          module will be called renesas-usbhs.
 
-config USB_WHCI_HCD
-       tristate "Wireless USB Host Controller Interface (WHCI) driver"
-       depends on USB_PCI && USB && UWB
-       select USB_WUSB
-       select UWB_WHCI
-       help
-         A driver for PCI-based Wireless USB Host Controllers that are
-         compliant with the WHCI specification.
-
-         To compile this driver a module, choose M here: the module
-         will be called "whci-hcd".
-
-config USB_HWA_HCD
-       tristate "Host Wire Adapter (HWA) driver"
-       depends on USB && UWB
-       select USB_WUSB
-       select UWB_HWA
-       help
-         This driver enables you to connect Wireless USB devices to
-         your system using a Host Wire Adaptor USB dongle. This is an
-         UWB Radio Controller and WUSB Host Controller connected to
-         your machine via USB (specified in WUSB1.0).
-
-         To compile this driver a module, choose M here: the module
-         will be called "hwa-hc".
-
 config USB_IMX21_HCD
        tristate "i.MX21 HCD support"
        depends on ARM && ARCH_MXC
index 84514f71ae4403a68ab56b25bff4815d89caf475..59b39e6b350b3ebf26b696be97512d32ec02c519 100644 (file)
@@ -35,8 +35,6 @@ ifneq ($(CONFIG_DEBUG_FS),)
        xhci-hcd-y              += xhci-debugfs.o
 endif
 
-obj-$(CONFIG_USB_WHCI_HCD)     += whci/
-
 obj-$(CONFIG_USB_PCI)  += pci-quirks.o
 
 obj-$(CONFIG_USB_EHCI_HCD)     += ehci-hcd.o
@@ -82,7 +80,6 @@ obj-$(CONFIG_USB_SL811_HCD)   += sl811-hcd.o
 obj-$(CONFIG_USB_SL811_CS)     += sl811_cs.o
 obj-$(CONFIG_USB_U132_HCD)     += u132-hcd.o
 obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-obj-$(CONFIG_USB_HWA_HCD)      += hwa-hc.o
 obj-$(CONFIG_USB_IMX21_HCD)    += imx21-hcd.o
 obj-$(CONFIG_USB_FSL_USB2)     += fsl-mph-dr-of.o
 obj-$(CONFIG_USB_EHCI_FSL)     += fsl-mph-dr-of.o
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
deleted file mode 100644 (file)
index 6968b9f..0000000
+++ /dev/null
@@ -1,875 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Host Wire Adapter:
- * Driver glue, HWA-specific functions, bridges to WAHC and WUSBHC
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * The HWA driver is a simple layer that forwards requests to the WAHC
- * (Wire Adater Host Controller) or WUSBHC (Wireless USB Host
- * Controller) layers.
- *
- * Host Wire Adapter is the 'WUSB 1.0 standard' name for Wireless-USB
- * Host Controller that is connected to your system via USB (a USB
- * dongle that implements a USB host...). There is also a Device Wired
- * Adaptor, DWA (Wireless USB hub) that uses the same mechanism for
- * transferring data (it is after all a USB host connected via
- * Wireless USB), we have a common layer called Wire Adapter Host
- * Controller that does all the hard work. The WUSBHC (Wireless USB
- * Host Controller) is the part common to WUSB Host Controllers, the
- * HWA and the PCI-based one, that is implemented following the WHCI
- * spec. All these layers are implemented in ../wusbcore.
- *
- * The main functions are hwahc_op_urb_{en,de}queue(), that pass the
- * job of converting a URB to a Wire Adapter
- *
- * Entry points:
- *
- *   hwahc_driver_*()   Driver initialization, registration and
- *                      teardown.
- *
- *   hwahc_probe()     New device came up, create an instance for
- *                      it [from device enumeration].
- *
- *   hwahc_disconnect()        Remove device instance [from device
- *                      enumeration].
- *
- *   [__]hwahc_op_*()   Host-Wire-Adaptor specific functions for
- *                      starting/stopping/etc (some might be made also
- *                      DWA).
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/workqueue.h>
-#include <linux/wait.h>
-#include <linux/completion.h>
-#include "../wusbcore/wa-hc.h"
-#include "../wusbcore/wusbhc.h"
-
-struct hwahc {
-       struct wusbhc wusbhc;   /* has to be 1st */
-       struct wahc wa;
-};
-
-/*
- * FIXME should be wusbhc
- *
- * NOTE: we need to cache the Cluster ID because later...there is no
- *       way to get it :)
- */
-static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id)
-{
-       int result;
-       struct wusbhc *wusbhc = &hwahc->wusbhc;
-       struct wahc *wa = &hwahc->wa;
-       struct device *dev = &wa->usb_iface->dev;
-
-       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_SET_CLUSTER_ID,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       cluster_id,
-                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0)
-               dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n",
-                       cluster_id, result);
-       else
-               wusbhc->cluster_id = cluster_id;
-       dev_info(dev, "Wireless USB Cluster ID set to 0x%02x\n", cluster_id);
-       return result;
-}
-
-static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
-{
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-
-       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_SET_NUM_DNTS,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       interval << 8 | slots,
-                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Reset a WUSB host controller and wait for it to complete doing it.
- *
- * @usb_hcd:   Pointer to WUSB Host Controller instance.
- *
- */
-static int hwahc_op_reset(struct usb_hcd *usb_hcd)
-{
-       int result;
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct device *dev = &hwahc->wa.usb_iface->dev;
-
-       mutex_lock(&wusbhc->mutex);
-       wa_nep_disarm(&hwahc->wa);
-       result = __wa_set_feature(&hwahc->wa, WA_RESET);
-       if (result < 0) {
-               dev_err(dev, "error commanding HC to reset: %d\n", result);
-               goto error_unlock;
-       }
-       result = __wa_wait_status(&hwahc->wa, WA_STATUS_RESETTING, 0);
-       if (result < 0) {
-               dev_err(dev, "error waiting for HC to reset: %d\n", result);
-               goto error_unlock;
-       }
-error_unlock:
-       mutex_unlock(&wusbhc->mutex);
-       return result;
-}
-
-/*
- * FIXME: break this function up
- */
-static int hwahc_op_start(struct usb_hcd *usb_hcd)
-{
-       u8 addr;
-       int result;
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       result = -ENOSPC;
-       mutex_lock(&wusbhc->mutex);
-       addr = wusb_cluster_id_get();
-       if (addr == 0)
-               goto error_cluster_id_get;
-       result = __hwahc_set_cluster_id(hwahc, addr);
-       if (result < 0)
-               goto error_set_cluster_id;
-
-       usb_hcd->uses_new_polling = 1;
-       set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
-       usb_hcd->state = HC_STATE_RUNNING;
-
-       /*
-        * prevent USB core from suspending the root hub since
-        * bus_suspend and bus_resume are not yet supported.
-        */
-       pm_runtime_get_noresume(&usb_hcd->self.root_hub->dev);
-
-       result = 0;
-out:
-       mutex_unlock(&wusbhc->mutex);
-       return result;
-
-error_set_cluster_id:
-       wusb_cluster_id_put(addr);
-error_cluster_id_get:
-       goto out;
-
-}
-
-/*
- * No need to abort pipes, as when this is called, all the children
- * has been disconnected and that has done it [through
- * usb_disable_interface() -> usb_disable_endpoint() ->
- * hwahc_op_ep_disable() - >rpipe_ep_disable()].
- */
-static void hwahc_op_stop(struct usb_hcd *usb_hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-
-       mutex_lock(&wusbhc->mutex);
-       wusb_cluster_id_put(wusbhc->cluster_id);
-       mutex_unlock(&wusbhc->mutex);
-}
-
-static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-
-       /*
-        * We cannot query the HWA for the WUSB time since that requires sending
-        * a synchronous URB and this function can be called in_interrupt.
-        * Instead, query the USB frame number for our parent and use that.
-        */
-       return usb_get_current_frame_number(wa->usb_dev);
-}
-
-static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
-                               gfp_t gfp)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       return wa_urb_enqueue(&hwahc->wa, urb->ep, urb, gfp);
-}
-
-static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb,
-                               int status)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       return wa_urb_dequeue(&hwahc->wa, urb, status);
-}
-
-/*
- * Release resources allocated for an endpoint
- *
- * If there is an associated rpipe to this endpoint, go ahead and put it.
- */
-static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd,
-                                     struct usb_host_endpoint *ep)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       rpipe_ep_disable(&hwahc->wa, ep);
-}
-
-static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)
-{
-       int result;
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct device *dev = &hwahc->wa.usb_iface->dev;
-
-       result = __wa_set_feature(&hwahc->wa, WA_ENABLE);
-       if (result < 0) {
-               dev_err(dev, "error commanding HC to start: %d\n", result);
-               goto error_stop;
-       }
-       result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE);
-       if (result < 0) {
-               dev_err(dev, "error waiting for HC to start: %d\n", result);
-               goto error_stop;
-       }
-       result = wa_nep_arm(&hwahc->wa, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "cannot listen to notifications: %d\n", result);
-               goto error_stop;
-       }
-       /*
-        * If WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS is set,
-        *  disable transfer notifications.
-        */
-       if (hwahc->wa.quirks &
-               WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS) {
-               struct usb_host_interface *cur_altsetting =
-                       hwahc->wa.usb_iface->cur_altsetting;
-
-               result = usb_control_msg(hwahc->wa.usb_dev,
-                               usb_sndctrlpipe(hwahc->wa.usb_dev, 0),
-                               WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS,
-                               USB_DIR_OUT | USB_TYPE_VENDOR |
-                                       USB_RECIP_INTERFACE,
-                               WA_REQ_ALEREON_FEATURE_SET,
-                               cur_altsetting->desc.bInterfaceNumber,
-                               NULL, 0,
-                               USB_CTRL_SET_TIMEOUT);
-               /*
-                * If we successfully sent the control message, start DTI here
-                * because no transfer notifications will be received which is
-                * where DTI is normally started.
-                */
-               if (result == 0)
-                       result = wa_dti_start(&hwahc->wa);
-               else
-                       result = 0;     /* OK.  Continue normally. */
-
-               if (result < 0) {
-                       dev_err(dev, "cannot start DTI: %d\n", result);
-                       goto error_dti_start;
-               }
-       }
-
-       return result;
-
-error_dti_start:
-       wa_nep_disarm(&hwahc->wa);
-error_stop:
-       __wa_clear_feature(&hwahc->wa, WA_ENABLE);
-       return result;
-}
-
-static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay)
-{
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       int ret;
-
-       ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                             WUSB_REQ_CHAN_STOP,
-                             USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                             delay * 1000,
-                             iface_no,
-                             NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (ret == 0)
-               msleep(delay);
-
-       wa_nep_disarm(&hwahc->wa);
-       __wa_stop(&hwahc->wa);
-}
-
-/*
- * Set the UWB MAS allocation for the WUSB cluster
- *
- * @stream_index: stream to use (-1 for cancelling the allocation)
- * @mas: mas bitmap to use
- */
-static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index,
-                             const struct uwb_mas_bm *mas)
-{
-       int result;
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       struct device *dev = &wa->usb_iface->dev;
-       u8 mas_le[UWB_NUM_MAS/8];
-
-       /* Set the stream index */
-       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_SET_STREAM_IDX,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       stream_index,
-                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Cannot set WUSB stream index: %d\n", result);
-               goto out;
-       }
-       uwb_mas_bm_copy_le(mas_le, mas);
-       /* Set the MAS allocation */
-       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_SET_WUSB_MAS,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       mas_le, 32, USB_CTRL_SET_TIMEOUT);
-       if (result < 0)
-               dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result);
-out:
-       return result;
-}
-
-/*
- * Add an IE to the host's MMC
- *
- * @interval:    See WUSB1.0[8.5.3.1]
- * @repeat_cnt:  See WUSB1.0[8.5.3.1]
- * @handle:      See WUSB1.0[8.5.3.1]
- * @wuie:        Pointer to the header of the WUSB IE data to add.
- *               MUST BE allocated in a kmalloc buffer (no stack or
- *               vmalloc).
- *
- * NOTE: the format of the WUSB IEs for MMCs are different to the
- *       normal MBOA MAC IEs (IE Id + Length in MBOA MAC vs. Length +
- *       Id in WUSB IEs). Standards...you gotta love'em.
- */
-static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval,
-                               u8 repeat_cnt, u8 handle,
-                               struct wuie_hdr *wuie)
-{
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-
-       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_ADD_MMC_IE,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       interval << 8 | repeat_cnt,
-                       handle << 8 | iface_no,
-                       wuie, wuie->bLength, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Remove an IE to the host's MMC
- *
- * @handle:      See WUSB1.0[8.5.3.1]
- */
-static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
-{
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_REMOVE_MMC_IE,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       0, handle << 8 | iface_no,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Update device information for a given fake port
- *
- * @port_idx: Fake port to which device is connected (wusbhc index, not
- *            USB port number).
- */
-static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc,
-                                  struct wusb_dev *wusb_dev)
-{
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       struct hwa_dev_info *dev_info;
-       int ret;
-
-       /* fill out the Device Info buffer and send it */
-       dev_info = kzalloc(sizeof(struct hwa_dev_info), GFP_KERNEL);
-       if (!dev_info)
-               return -ENOMEM;
-       uwb_mas_bm_copy_le(dev_info->bmDeviceAvailability,
-                          &wusb_dev->availability);
-       dev_info->bDeviceAddress = wusb_dev->addr;
-
-       /*
-        * If the descriptors haven't been read yet, use a default PHY
-        * rate of 53.3 Mbit/s only.  The correct value will be used
-        * when this will be called again as part of the
-        * authentication process (which occurs after the descriptors
-        * have been read).
-        */
-       if (wusb_dev->wusb_cap_descr)
-               dev_info->wPHYRates = wusb_dev->wusb_cap_descr->wPHYRates;
-       else
-               dev_info->wPHYRates = cpu_to_le16(USB_WIRELESS_PHY_53);
-
-       ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       WUSB_REQ_SET_DEV_INFO,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       0, wusb_dev->port_idx << 8 | iface_no,
-                       dev_info, sizeof(struct hwa_dev_info),
-                       USB_CTRL_SET_TIMEOUT);
-       kfree(dev_info);
-       return ret;
-}
-
-/*
- * Set host's idea of which encryption (and key) method to use when
- * talking to ad evice on a given port.
- *
- * If key is NULL, it means disable encryption for that "virtual port"
- * (used when we disconnect).
- */
-static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
-                              const void *key, size_t key_size,
-                              u8 key_idx)
-{
-       int result = -ENOMEM;
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       struct usb_key_descriptor *keyd;
-       size_t keyd_len;
-
-       keyd_len = sizeof(*keyd) + key_size;
-       keyd = kzalloc(keyd_len, GFP_KERNEL);
-       if (keyd == NULL)
-               return -ENOMEM;
-
-       keyd->bLength = keyd_len;
-       keyd->bDescriptorType = USB_DT_KEY;
-       keyd->tTKID[0] = (tkid >>  0) & 0xff;
-       keyd->tTKID[1] = (tkid >>  8) & 0xff;
-       keyd->tTKID[2] = (tkid >> 16) & 0xff;
-       memcpy(keyd->bKeyData, key, key_size);
-
-       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       USB_REQ_SET_DESCRIPTOR,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       USB_DT_KEY << 8 | key_idx,
-                       port_idx << 8 | iface_no,
-                       keyd, keyd_len, USB_CTRL_SET_TIMEOUT);
-
-       kzfree(keyd); /* clear keys etc. */
-       return result;
-}
-
-/*
- * Set host's idea of which encryption (and key) method to use when
- * talking to ad evice on a given port.
- *
- * If key is NULL, it means disable encryption for that "virtual port"
- * (used when we disconnect).
- */
-static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
-                             const void *key, size_t key_size)
-{
-       int result = -ENOMEM;
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       struct wahc *wa = &hwahc->wa;
-       u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       u8 encryption_value;
-
-       /* Tell the host which key to use to talk to the device */
-       if (key) {
-               u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_PTK,
-                                           WUSB_KEY_INDEX_ORIGINATOR_HOST);
-
-               result = __hwahc_dev_set_key(wusbhc, port_idx, tkid,
-                                            key, key_size, key_idx);
-               if (result < 0)
-                       goto error_set_key;
-               encryption_value = wusbhc->ccm1_etd->bEncryptionValue;
-       } else {
-               /* FIXME: this should come from wusbhc->etd[UNSECURE].value */
-               encryption_value = 0;
-       }
-
-       /* Set the encryption type for communicating with the device */
-       result = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       USB_REQ_SET_ENCRYPTION,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       encryption_value, port_idx << 8 | iface_no,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0)
-               dev_err(wusbhc->dev, "Can't set host's WUSB encryption for "
-                       "port index %u to %s (value %d): %d\n", port_idx,
-                       wusb_et_name(wusbhc->ccm1_etd->bEncryptionType),
-                       wusbhc->ccm1_etd->bEncryptionValue, result);
-error_set_key:
-       return result;
-}
-
-/*
- * Set host's GTK key
- */
-static int __hwahc_op_set_gtk(struct wusbhc *wusbhc, u32 tkid,
-                             const void *key, size_t key_size)
-{
-       u8 key_idx = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK,
-                                   WUSB_KEY_INDEX_ORIGINATOR_HOST);
-
-       return __hwahc_dev_set_key(wusbhc, 0, tkid, key, key_size, key_idx);
-}
-
-/*
- * Get the Wire Adapter class-specific descriptor
- *
- * NOTE: this descriptor comes with the big bundled configuration
- *       descriptor that includes the interfaces' and endpoints', so
- *       we just look for it in the cached copy kept by the USB stack.
- *
- * NOTE2: We convert LE fields to CPU order.
- */
-static int wa_fill_descr(struct wahc *wa)
-{
-       int result;
-       struct device *dev = &wa->usb_iface->dev;
-       char *itr;
-       struct usb_device *usb_dev = wa->usb_dev;
-       struct usb_descriptor_header *hdr;
-       struct usb_wa_descriptor *wa_descr;
-       size_t itr_size, actconfig_idx;
-
-       actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
-                       sizeof(usb_dev->config[0]);
-       itr = usb_dev->rawdescriptors[actconfig_idx];
-       itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
-       while (itr_size >= sizeof(*hdr)) {
-               hdr = (struct usb_descriptor_header *) itr;
-               dev_dbg(dev, "Extra device descriptor: "
-                       "type %02x/%u bytes @ %zu (%zu left)\n",
-                       hdr->bDescriptorType, hdr->bLength,
-                       (itr - usb_dev->rawdescriptors[actconfig_idx]),
-                       itr_size);
-               if (hdr->bDescriptorType == USB_DT_WIRE_ADAPTER)
-                       goto found;
-               itr += hdr->bLength;
-               itr_size -= hdr->bLength;
-       }
-       dev_err(dev, "cannot find Wire Adapter Class descriptor\n");
-       return -ENODEV;
-
-found:
-       result = -EINVAL;
-       if (hdr->bLength > itr_size) {  /* is it available? */
-               dev_err(dev, "incomplete Wire Adapter Class descriptor "
-                       "(%zu bytes left, %u needed)\n",
-                       itr_size, hdr->bLength);
-               goto error;
-       }
-       if (hdr->bLength < sizeof(*wa->wa_descr)) {
-               dev_err(dev, "short Wire Adapter Class descriptor\n");
-               goto error;
-       }
-       wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr;
-       if (le16_to_cpu(wa_descr->bcdWAVersion) > 0x0100)
-               dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n",
-                        (le16_to_cpu(wa_descr->bcdWAVersion) & 0xff00) >> 8,
-                        le16_to_cpu(wa_descr->bcdWAVersion) & 0x00ff);
-       result = 0;
-error:
-       return result;
-}
-
-static const struct hc_driver hwahc_hc_driver = {
-       .description = "hwa-hcd",
-       .product_desc = "Wireless USB HWA host controller",
-       .hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd),
-       .irq = NULL,                    /* FIXME */
-       .flags = HCD_USB25,
-       .reset = hwahc_op_reset,
-       .start = hwahc_op_start,
-       .stop = hwahc_op_stop,
-       .get_frame_number = hwahc_op_get_frame_number,
-       .urb_enqueue = hwahc_op_urb_enqueue,
-       .urb_dequeue = hwahc_op_urb_dequeue,
-       .endpoint_disable = hwahc_op_endpoint_disable,
-
-       .hub_status_data = wusbhc_rh_status_data,
-       .hub_control = wusbhc_rh_control,
-       .start_port_reset = wusbhc_rh_start_port_reset,
-};
-
-static int hwahc_security_create(struct hwahc *hwahc)
-{
-       int result;
-       struct wusbhc *wusbhc = &hwahc->wusbhc;
-       struct usb_device *usb_dev = hwahc->wa.usb_dev;
-       struct device *dev = &usb_dev->dev;
-       struct usb_security_descriptor *secd;
-       struct usb_encryption_descriptor *etd;
-       void *itr, *top;
-       size_t itr_size, needed, bytes;
-       u8 index;
-       char buf[64];
-
-       /* Find the host's security descriptors in the config descr bundle */
-       index = (usb_dev->actconfig - usb_dev->config) /
-               sizeof(usb_dev->config[0]);
-       itr = usb_dev->rawdescriptors[index];
-       itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
-       top = itr + itr_size;
-       result = __usb_get_extra_descriptor(usb_dev->rawdescriptors[index],
-                       le16_to_cpu(usb_dev->actconfig->desc.wTotalLength),
-                       USB_DT_SECURITY, (void **) &secd, sizeof(*secd));
-       if (result == -1) {
-               dev_warn(dev, "BUG? WUSB host has no security descriptors\n");
-               return 0;
-       }
-       needed = sizeof(*secd);
-       if (top - (void *)secd < needed) {
-               dev_err(dev, "BUG? Not enough data to process security "
-                       "descriptor header (%zu bytes left vs %zu needed)\n",
-                       top - (void *) secd, needed);
-               return 0;
-       }
-       needed = le16_to_cpu(secd->wTotalLength);
-       if (top - (void *)secd < needed) {
-               dev_err(dev, "BUG? Not enough data to process security "
-                       "descriptors (%zu bytes left vs %zu needed)\n",
-                       top - (void *) secd, needed);
-               return 0;
-       }
-       /* Walk over the sec descriptors and store CCM1's on wusbhc */
-       itr = (void *) secd + sizeof(*secd);
-       top = (void *) secd + le16_to_cpu(secd->wTotalLength);
-       index = 0;
-       bytes = 0;
-       while (itr < top) {
-               etd = itr;
-               if (top - itr < sizeof(*etd)) {
-                       dev_err(dev, "BUG: bad host security descriptor; "
-                               "not enough data (%zu vs %zu left)\n",
-                               top - itr, sizeof(*etd));
-                       break;
-               }
-               if (etd->bLength < sizeof(*etd)) {
-                       dev_err(dev, "BUG: bad host encryption descriptor; "
-                               "descriptor is too short "
-                               "(%zu vs %zu needed)\n",
-                               (size_t)etd->bLength, sizeof(*etd));
-                       break;
-               }
-               itr += etd->bLength;
-               bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
-                                 "%s (0x%02x) ",
-                                 wusb_et_name(etd->bEncryptionType),
-                                 etd->bEncryptionValue);
-               wusbhc->ccm1_etd = etd;
-       }
-       dev_info(dev, "supported encryption types: %s\n", buf);
-       if (wusbhc->ccm1_etd == NULL) {
-               dev_err(dev, "E: host doesn't support CCM-1 crypto\n");
-               return 0;
-       }
-       /* Pretty print what we support */
-       return 0;
-}
-
-static void hwahc_security_release(struct hwahc *hwahc)
-{
-       /* nothing to do here so far... */
-}
-
-static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface,
-       kernel_ulong_t quirks)
-{
-       int result;
-       struct device *dev = &iface->dev;
-       struct wusbhc *wusbhc = &hwahc->wusbhc;
-       struct wahc *wa = &hwahc->wa;
-       struct usb_device *usb_dev = interface_to_usbdev(iface);
-
-       wa->usb_dev = usb_get_dev(usb_dev);     /* bind the USB device */
-       wa->usb_iface = usb_get_intf(iface);
-       wusbhc->dev = dev;
-       /* defer getting the uwb_rc handle until it is needed since it
-        * may not have been registered by the hwa_rc driver yet. */
-       wusbhc->uwb_rc = NULL;
-       result = wa_fill_descr(wa);     /* Get the device descriptor */
-       if (result < 0)
-               goto error_fill_descriptor;
-       if (wa->wa_descr->bNumPorts > USB_MAXCHILDREN) {
-               dev_err(dev, "FIXME: USB_MAXCHILDREN too low for WUSB "
-                       "adapter (%u ports)\n", wa->wa_descr->bNumPorts);
-               wusbhc->ports_max = USB_MAXCHILDREN;
-       } else {
-               wusbhc->ports_max = wa->wa_descr->bNumPorts;
-       }
-       wusbhc->mmcies_max = wa->wa_descr->bNumMMCIEs;
-       wusbhc->start = __hwahc_op_wusbhc_start;
-       wusbhc->stop = __hwahc_op_wusbhc_stop;
-       wusbhc->mmcie_add = __hwahc_op_mmcie_add;
-       wusbhc->mmcie_rm = __hwahc_op_mmcie_rm;
-       wusbhc->dev_info_set = __hwahc_op_dev_info_set;
-       wusbhc->bwa_set = __hwahc_op_bwa_set;
-       wusbhc->set_num_dnts = __hwahc_op_set_num_dnts;
-       wusbhc->set_ptk = __hwahc_op_set_ptk;
-       wusbhc->set_gtk = __hwahc_op_set_gtk;
-       result = hwahc_security_create(hwahc);
-       if (result < 0) {
-               dev_err(dev, "Can't initialize security: %d\n", result);
-               goto error_security_create;
-       }
-       wa->wusb = wusbhc;      /* FIXME: ugly, need to fix */
-       result = wusbhc_create(&hwahc->wusbhc);
-       if (result < 0) {
-               dev_err(dev, "Can't create WUSB HC structures: %d\n", result);
-               goto error_wusbhc_create;
-       }
-       result = wa_create(&hwahc->wa, iface, quirks);
-       if (result < 0)
-               goto error_wa_create;
-       return 0;
-
-error_wa_create:
-       wusbhc_destroy(&hwahc->wusbhc);
-error_wusbhc_create:
-       /* WA Descr fill allocs no resources */
-error_security_create:
-error_fill_descriptor:
-       usb_put_intf(iface);
-       usb_put_dev(usb_dev);
-       return result;
-}
-
-static void hwahc_destroy(struct hwahc *hwahc)
-{
-       struct wusbhc *wusbhc = &hwahc->wusbhc;
-
-       mutex_lock(&wusbhc->mutex);
-       __wa_destroy(&hwahc->wa);
-       wusbhc_destroy(&hwahc->wusbhc);
-       hwahc_security_release(hwahc);
-       hwahc->wusbhc.dev = NULL;
-       uwb_rc_put(wusbhc->uwb_rc);
-       usb_put_intf(hwahc->wa.usb_iface);
-       usb_put_dev(hwahc->wa.usb_dev);
-       mutex_unlock(&wusbhc->mutex);
-}
-
-static void hwahc_init(struct hwahc *hwahc)
-{
-       wa_init(&hwahc->wa);
-}
-
-static int hwahc_probe(struct usb_interface *usb_iface,
-                      const struct usb_device_id *id)
-{
-       int result;
-       struct usb_hcd *usb_hcd;
-       struct wusbhc *wusbhc;
-       struct hwahc *hwahc;
-       struct device *dev = &usb_iface->dev;
-
-       result = -ENOMEM;
-       usb_hcd = usb_create_hcd(&hwahc_hc_driver, &usb_iface->dev, "wusb-hwa");
-       if (usb_hcd == NULL) {
-               dev_err(dev, "unable to allocate instance\n");
-               goto error_alloc;
-       }
-       usb_hcd->wireless = 1;
-       usb_hcd->self.sg_tablesize = ~0;
-       wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       hwahc_init(hwahc);
-       result = hwahc_create(hwahc, usb_iface, id->driver_info);
-       if (result < 0) {
-               dev_err(dev, "Cannot initialize internals: %d\n", result);
-               goto error_hwahc_create;
-       }
-       result = usb_add_hcd(usb_hcd, 0, 0);
-       if (result < 0) {
-               dev_err(dev, "Cannot add HCD: %d\n", result);
-               goto error_add_hcd;
-       }
-       device_wakeup_enable(usb_hcd->self.controller);
-       result = wusbhc_b_create(&hwahc->wusbhc);
-       if (result < 0) {
-               dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result);
-               goto error_wusbhc_b_create;
-       }
-       return 0;
-
-error_wusbhc_b_create:
-       usb_remove_hcd(usb_hcd);
-error_add_hcd:
-       hwahc_destroy(hwahc);
-error_hwahc_create:
-       usb_put_hcd(usb_hcd);
-error_alloc:
-       return result;
-}
-
-static void hwahc_disconnect(struct usb_interface *usb_iface)
-{
-       struct usb_hcd *usb_hcd;
-       struct wusbhc *wusbhc;
-       struct hwahc *hwahc;
-
-       usb_hcd = usb_get_intfdata(usb_iface);
-       wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       wusbhc_b_destroy(&hwahc->wusbhc);
-       usb_remove_hcd(usb_hcd);
-       hwahc_destroy(hwahc);
-       usb_put_hcd(usb_hcd);
-}
-
-static const struct usb_device_id hwahc_id_table[] = {
-       /* Alereon 5310 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01),
-         .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
-               WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
-       /* Alereon 5611 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x02, 0x01),
-         .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC |
-               WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },
-       /* FIXME: use class labels for this */
-       { USB_INTERFACE_INFO(0xe0, 0x02, 0x01), },
-       {},
-};
-MODULE_DEVICE_TABLE(usb, hwahc_id_table);
-
-static struct usb_driver hwahc_driver = {
-       .name =         "hwa-hc",
-       .probe =        hwahc_probe,
-       .disconnect =   hwahc_disconnect,
-       .id_table =     hwahc_id_table,
-};
-
-module_usb_driver(hwahc_driver);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Host Wired Adapter USB Host Control Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/whci/Makefile b/drivers/usb/host/whci/Makefile
deleted file mode 100644 (file)
index 859d200..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-
-obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o
-
-whci-hcd-y := \
-       asl.o   \
-       debug.o \
-       hcd.o   \
-       hw.o    \
-       init.o  \
-       int.o   \
-       pzl.o   \
-       qset.o  \
-       wusb.o
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c
deleted file mode 100644 (file)
index 276fb34..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) asynchronous schedule management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/dma-mapping.h>
-#include <linux/uwb/umc.h>
-#include <linux/usb.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset,
-                              struct whc_qset **next, struct whc_qset **prev)
-{
-       struct list_head *n, *p;
-
-       BUG_ON(list_empty(&whc->async_list));
-
-       n = qset->list_node.next;
-       if (n == &whc->async_list)
-               n = n->next;
-       p = qset->list_node.prev;
-       if (p == &whc->async_list)
-               p = p->prev;
-
-       *next = container_of(n, struct whc_qset, list_node);
-       *prev = container_of(p, struct whc_qset, list_node);
-
-}
-
-static void asl_qset_insert_begin(struct whc *whc, struct whc_qset *qset)
-{
-       list_move(&qset->list_node, &whc->async_list);
-       qset->in_sw_list = true;
-}
-
-static void asl_qset_insert(struct whc *whc, struct whc_qset *qset)
-{
-       struct whc_qset *next, *prev;
-
-       qset_clear(whc, qset);
-
-       /* Link into ASL. */
-       qset_get_next_prev(whc, qset, &next, &prev);
-       whc_qset_set_link_ptr(&qset->qh.link, next->qset_dma);
-       whc_qset_set_link_ptr(&prev->qh.link, qset->qset_dma);
-       qset->in_hw_list = true;
-}
-
-static void asl_qset_remove(struct whc *whc, struct whc_qset *qset)
-{
-       struct whc_qset *prev, *next;
-
-       qset_get_next_prev(whc, qset, &next, &prev);
-
-       list_move(&qset->list_node, &whc->async_removed_list);
-       qset->in_sw_list = false;
-
-       /*
-        * No more qsets in the ASL?  The caller must stop the ASL as
-        * it's no longer valid.
-        */
-       if (list_empty(&whc->async_list))
-               return;
-
-       /* Remove from ASL. */
-       whc_qset_set_link_ptr(&prev->qh.link, next->qset_dma);
-       qset->in_hw_list = false;
-}
-
-/**
- * process_qset - process any recently inactivated or halted qTDs in a
- * qset.
- *
- * After inactive qTDs are removed, new qTDs can be added if the
- * urb queue still contains URBs.
- *
- * Returns any additional WUSBCMD bits for the ASL sync command (i.e.,
- * WUSBCMD_ASYNC_QSET_RM if a halted qset was removed).
- */
-static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
-{
-       enum whc_update update = 0;
-       uint32_t status = 0;
-
-       while (qset->ntds) {
-               struct whc_qtd *td;
-
-               td = &qset->qtd[qset->td_start];
-               status = le32_to_cpu(td->status);
-
-               /*
-                * Nothing to do with a still active qTD.
-                */
-               if (status & QTD_STS_ACTIVE)
-                       break;
-
-               if (status & QTD_STS_HALTED) {
-                       /* Ug, an error. */
-                       process_halted_qtd(whc, qset, td);
-                       /* A halted qTD always triggers an update
-                          because the qset was either removed or
-                          reactivated. */
-                       update |= WHC_UPDATE_UPDATED;
-                       goto done;
-               }
-
-               /* Mmm, a completed qTD. */
-               process_inactive_qtd(whc, qset, td);
-       }
-
-       if (!qset->remove)
-               update |= qset_add_qtds(whc, qset);
-
-done:
-       /*
-        * Remove this qset from the ASL if requested, but only if has
-        * no qTDs.
-        */
-       if (qset->remove && qset->ntds == 0) {
-               asl_qset_remove(whc, qset);
-               update |= WHC_UPDATE_REMOVED;
-       }
-       return update;
-}
-
-void asl_start(struct whc *whc)
-{
-       struct whc_qset *qset;
-
-       qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
-
-       le_writeq(qset->qset_dma | QH_LINK_NTDS(8), whc->base + WUSBASYNCLISTADDR);
-
-       whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, WUSBCMD_ASYNC_EN);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
-                     WUSBSTS_ASYNC_SCHED, WUSBSTS_ASYNC_SCHED,
-                     1000, "start ASL");
-}
-
-void asl_stop(struct whc *whc)
-{
-       whc_write_wusbcmd(whc, WUSBCMD_ASYNC_EN, 0);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
-                     WUSBSTS_ASYNC_SCHED, 0,
-                     1000, "stop ASL");
-}
-
-/**
- * asl_update - request an ASL update and wait for the hardware to be synced
- * @whc: the WHCI HC
- * @wusbcmd: WUSBCMD value to start the update.
- *
- * If the WUSB HC is inactive (i.e., the ASL is stopped) then the
- * update must be skipped as the hardware may not respond to update
- * requests.
- */
-void asl_update(struct whc *whc, uint32_t wusbcmd)
-{
-       struct wusbhc *wusbhc = &whc->wusbhc;
-       long t;
-
-       mutex_lock(&wusbhc->mutex);
-       if (wusbhc->active) {
-               whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
-               t = wait_event_timeout(
-                       whc->async_list_wq,
-                       (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0,
-                       msecs_to_jiffies(1000));
-               if (t == 0)
-                       whc_hw_error(whc, "ASL update timeout");
-       }
-       mutex_unlock(&wusbhc->mutex);
-}
-
-/**
- * scan_async_work - scan the ASL for qsets to process.
- *
- * Process each qset in the ASL in turn and then signal the WHC that
- * the ASL has been updated.
- *
- * Then start, stop or update the asynchronous schedule as required.
- */
-void scan_async_work(struct work_struct *work)
-{
-       struct whc *whc = container_of(work, struct whc, async_work);
-       struct whc_qset *qset, *t;
-       enum whc_update update = 0;
-
-       spin_lock_irq(&whc->lock);
-
-       /*
-        * Transerve the software list backwards so new qsets can be
-        * safely inserted into the ASL without making it non-circular.
-        */
-       list_for_each_entry_safe_reverse(qset, t, &whc->async_list, list_node) {
-               if (!qset->in_hw_list) {
-                       asl_qset_insert(whc, qset);
-                       update |= WHC_UPDATE_ADDED;
-               }
-
-               update |= process_qset(whc, qset);
-       }
-
-       spin_unlock_irq(&whc->lock);
-
-       if (update) {
-               uint32_t wusbcmd = WUSBCMD_ASYNC_UPDATED | WUSBCMD_ASYNC_SYNCED_DB;
-               if (update & WHC_UPDATE_REMOVED)
-                       wusbcmd |= WUSBCMD_ASYNC_QSET_RM;
-               asl_update(whc, wusbcmd);
-       }
-
-       /*
-        * Now that the ASL is updated, complete the removal of any
-        * removed qsets.
-        *
-        * If the qset was to be reset, do so and reinsert it into the
-        * ASL if it has pending transfers.
-        */
-       spin_lock_irq(&whc->lock);
-
-       list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
-               qset_remove_complete(whc, qset);
-               if (qset->reset) {
-                       qset_reset(whc, qset);
-                       if (!list_empty(&qset->stds)) {
-                               asl_qset_insert_begin(whc, qset);
-                               queue_work(whc->workqueue, &whc->async_work);
-                       }
-               }
-       }
-
-       spin_unlock_irq(&whc->lock);
-}
-
-/**
- * asl_urb_enqueue - queue an URB onto the asynchronous list (ASL).
- * @whc: the WHCI host controller
- * @urb: the URB to enqueue
- * @mem_flags: flags for any memory allocations
- *
- * The qset for the endpoint is obtained and the urb queued on to it.
- *
- * Work is scheduled to update the hardware's view of the ASL.
- */
-int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
-{
-       struct whc_qset *qset;
-       int err;
-       unsigned long flags;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
-       if (err < 0) {
-               spin_unlock_irqrestore(&whc->lock, flags);
-               return err;
-       }
-
-       qset = get_qset(whc, urb, GFP_ATOMIC);
-       if (qset == NULL)
-               err = -ENOMEM;
-       else
-               err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
-       if (!err) {
-               if (!qset->in_sw_list && !qset->remove)
-                       asl_qset_insert_begin(whc, qset);
-       } else
-               usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
-
-       spin_unlock_irqrestore(&whc->lock, flags);
-
-       if (!err)
-               queue_work(whc->workqueue, &whc->async_work);
-
-       return err;
-}
-
-/**
- * asl_urb_dequeue - remove an URB (qset) from the async list.
- * @whc: the WHCI host controller
- * @urb: the URB to dequeue
- * @status: the current status of the URB
- *
- * URBs that do yet have qTDs can simply be removed from the software
- * queue, otherwise the qset must be removed from the ASL so the qTDs
- * can be removed.
- */
-int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
-{
-       struct whc_urb *wurb = urb->hcpriv;
-       struct whc_qset *qset = wurb->qset;
-       struct whc_std *std, *t;
-       bool has_qtd = false;
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
-       if (ret < 0)
-               goto out;
-
-       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
-               if (std->urb == urb) {
-                       if (std->qtd)
-                               has_qtd = true;
-                       qset_free_std(whc, std);
-               } else
-                       std->qtd = NULL; /* so this std is re-added when the qset is */
-       }
-
-       if (has_qtd) {
-               asl_qset_remove(whc, qset);
-               wurb->status = status;
-               wurb->is_async = true;
-               queue_work(whc->workqueue, &wurb->dequeue_work);
-       } else
-               qset_remove_urb(whc, qset, urb, status);
-out:
-       spin_unlock_irqrestore(&whc->lock, flags);
-
-       return ret;
-}
-
-/**
- * asl_qset_delete - delete a qset from the ASL
- */
-void asl_qset_delete(struct whc *whc, struct whc_qset *qset)
-{
-       qset->remove = 1;
-       queue_work(whc->workqueue, &whc->async_work);
-       qset_delete(whc, qset);
-}
-
-/**
- * asl_init - initialize the asynchronous schedule list
- *
- * A dummy qset with no qTDs is added to the ASL to simplify removing
- * qsets (no need to stop the ASL when the last qset is removed).
- */
-int asl_init(struct whc *whc)
-{
-       struct whc_qset *qset;
-
-       qset = qset_alloc(whc, GFP_KERNEL);
-       if (qset == NULL)
-               return -ENOMEM;
-
-       asl_qset_insert_begin(whc, qset);
-       asl_qset_insert(whc, qset);
-
-       return 0;
-}
-
-/**
- * asl_clean_up - free ASL resources
- *
- * The ASL is stopped and empty except for the dummy qset.
- */
-void asl_clean_up(struct whc *whc)
-{
-       struct whc_qset *qset;
-
-       if (!list_empty(&whc->async_list)) {
-               qset = list_first_entry(&whc->async_list, struct whc_qset, list_node);
-               list_del(&qset->list_node);
-               qset_free(whc, qset);
-       }
-}
diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c
deleted file mode 100644 (file)
index 8ddfe3f..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) debug.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/export.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-struct whc_dbg {
-       struct dentry *di_f;
-       struct dentry *asl_f;
-       struct dentry *pzl_f;
-};
-
-static void qset_print(struct seq_file *s, struct whc_qset *qset)
-{
-       static const char *qh_type[] = {
-               "ctrl", "isoc", "bulk", "intr", "rsvd", "rsvd", "rsvd", "lpintr", };
-       struct whc_std *std;
-       struct urb *urb = NULL;
-       int i;
-
-       seq_printf(s, "qset %08x", (u32)qset->qset_dma);
-       if (&qset->list_node == qset->whc->async_list.prev) {
-               seq_printf(s, " (dummy)\n");
-       } else {
-               seq_printf(s, " ep%d%s-%s maxpkt: %d\n",
-                          qset->qh.info1 & 0x0f,
-                          (qset->qh.info1 >> 4) & 0x1 ? "in" : "out",
-                          qh_type[(qset->qh.info1 >> 5) & 0x7],
-                          (qset->qh.info1 >> 16) & 0xffff);
-       }
-       seq_printf(s, "  -> %08x\n", (u32)qset->qh.link);
-       seq_printf(s, "  info: %08x %08x %08x\n",
-                  qset->qh.info1, qset->qh.info2,  qset->qh.info3);
-       seq_printf(s, "  sts: %04x errs: %d curwin: %08x\n",
-                  qset->qh.status, qset->qh.err_count, qset->qh.cur_window);
-       seq_printf(s, "  TD: sts: %08x opts: %08x\n",
-                  qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options);
-
-       for (i = 0; i < WHCI_QSET_TD_MAX; i++) {
-               seq_printf(s, "  %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n",
-                       i == qset->td_start ? 'S' : ' ',
-                       i == qset->td_end ? 'E' : ' ',
-                       i, qset->qtd[i].status, qset->qtd[i].options,
-                       (u32)qset->qtd[i].page_list_ptr);
-       }
-       seq_printf(s, "  ntds: %d\n", qset->ntds);
-       list_for_each_entry(std, &qset->stds, list_node) {
-               if (urb != std->urb) {
-                       urb = std->urb;
-                       seq_printf(s, "  urb %p transferred: %d bytes\n", urb,
-                               urb->actual_length);
-               }
-               if (std->qtd)
-                       seq_printf(s, "    sTD[%td]: %zu bytes @ %08x\n",
-                               std->qtd - &qset->qtd[0],
-                               std->len, std->num_pointers ?
-                               (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
-               else
-                       seq_printf(s, "    sTD[-]: %zd bytes @ %08x\n",
-                               std->len, std->num_pointers ?
-                               (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr);
-       }
-}
-
-static int di_show(struct seq_file *s, void *p)
-{
-       struct whc *whc = s->private;
-       int d;
-
-       for (d = 0; d < whc->n_devices; d++) {
-               struct di_buf_entry *di = &whc->di_buf[d];
-
-               seq_printf(s, "DI[%d]\n", d);
-               seq_printf(s, "  availability: %*pb\n",
-                          UWB_NUM_MAS, (unsigned long *)di->availability_info);
-               seq_printf(s, "  %c%c key idx: %d dev addr: %d\n",
-                          (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
-                          (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
-                          (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8,
-                          (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK));
-       }
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(di);
-
-static int asl_show(struct seq_file *s, void *p)
-{
-       struct whc *whc = s->private;
-       struct whc_qset *qset;
-
-       list_for_each_entry(qset, &whc->async_list, list_node) {
-               qset_print(s, qset);
-       }
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(asl);
-
-static int pzl_show(struct seq_file *s, void *p)
-{
-       struct whc *whc = s->private;
-       struct whc_qset *qset;
-       int period;
-
-       for (period = 0; period < 5; period++) {
-               seq_printf(s, "Period %d\n", period);
-               list_for_each_entry(qset, &whc->periodic_list[period], list_node) {
-                       qset_print(s, qset);
-               }
-       }
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(pzl);
-
-void whc_dbg_init(struct whc *whc)
-{
-       if (whc->wusbhc.pal.debugfs_dir == NULL)
-               return;
-
-       whc->dbg = kzalloc(sizeof(struct whc_dbg), GFP_KERNEL);
-       if (whc->dbg == NULL)
-               return;
-
-       whc->dbg->di_f = debugfs_create_file("di", 0444,
-                                             whc->wusbhc.pal.debugfs_dir, whc,
-                                             &di_fops);
-       whc->dbg->asl_f = debugfs_create_file("asl", 0444,
-                                             whc->wusbhc.pal.debugfs_dir, whc,
-                                             &asl_fops);
-       whc->dbg->pzl_f = debugfs_create_file("pzl", 0444,
-                                             whc->wusbhc.pal.debugfs_dir, whc,
-                                             &pzl_fops);
-}
-
-void whc_dbg_clean_up(struct whc *whc)
-{
-       if (whc->dbg) {
-               debugfs_remove(whc->dbg->pzl_f);
-               debugfs_remove(whc->dbg->asl_f);
-               debugfs_remove(whc->dbg->di_f);
-               kfree(whc->dbg);
-       }
-}
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c
deleted file mode 100644 (file)
index 8af9dcf..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) driver.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/uwb/umc.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-/*
- * One time initialization.
- *
- * Nothing to do here.
- */
-static int whc_reset(struct usb_hcd *usb_hcd)
-{
-       return 0;
-}
-
-/*
- * Start the wireless host controller.
- *
- * Start device notification.
- *
- * Put hc into run state, set DNTS parameters.
- */
-static int whc_start(struct usb_hcd *usb_hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u8 bcid;
-       int ret;
-
-       mutex_lock(&wusbhc->mutex);
-
-       le_writel(WUSBINTR_GEN_CMD_DONE
-                 | WUSBINTR_HOST_ERR
-                 | WUSBINTR_ASYNC_SCHED_SYNCED
-                 | WUSBINTR_DNTS_INT
-                 | WUSBINTR_ERR_INT
-                 | WUSBINTR_INT,
-                 whc->base + WUSBINTR);
-
-       /* set cluster ID */
-       bcid = wusb_cluster_id_get();
-       ret = whc_set_cluster_id(whc, bcid);
-       if (ret < 0)
-               goto out;
-       wusbhc->cluster_id = bcid;
-
-       /* start HC */
-       whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN);
-
-       usb_hcd->uses_new_polling = 1;
-       set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
-       usb_hcd->state = HC_STATE_RUNNING;
-
-out:
-       mutex_unlock(&wusbhc->mutex);
-       return ret;
-}
-
-
-/*
- * Stop the wireless host controller.
- *
- * Stop device notification.
- *
- * Wait for pending transfer to stop? Put hc into stop state?
- */
-static void whc_stop(struct usb_hcd *usb_hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-
-       mutex_lock(&wusbhc->mutex);
-
-       /* stop HC */
-       le_writel(0, whc->base + WUSBINTR);
-       whc_write_wusbcmd(whc, WUSBCMD_RUN, 0);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
-                     WUSBSTS_HCHALTED, WUSBSTS_HCHALTED,
-                     100, "HC to halt");
-
-       wusb_cluster_id_put(wusbhc->cluster_id);
-
-       mutex_unlock(&wusbhc->mutex);
-}
-
-static int whc_get_frame_number(struct usb_hcd *usb_hcd)
-{
-       /* Frame numbers are not applicable to WUSB. */
-       return -ENOSYS;
-}
-
-
-/*
- * Queue an URB to the ASL or PZL
- */
-static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
-                          gfp_t mem_flags)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       int ret;
-
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_INTERRUPT:
-               ret = pzl_urb_enqueue(whc, urb, mem_flags);
-               break;
-       case PIPE_ISOCHRONOUS:
-               dev_err(&whc->umc->dev, "isochronous transfers unsupported\n");
-               ret = -ENOTSUPP;
-               break;
-       case PIPE_CONTROL:
-       case PIPE_BULK:
-       default:
-               ret = asl_urb_enqueue(whc, urb, mem_flags);
-               break;
-       }
-
-       return ret;
-}
-
-/*
- * Remove a queued URB from the ASL or PZL.
- */
-static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       int ret;
-
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_INTERRUPT:
-               ret = pzl_urb_dequeue(whc, urb, status);
-               break;
-       case PIPE_ISOCHRONOUS:
-               ret = -ENOTSUPP;
-               break;
-       case PIPE_CONTROL:
-       case PIPE_BULK:
-       default:
-               ret = asl_urb_dequeue(whc, urb, status);
-               break;
-       }
-
-       return ret;
-}
-
-/*
- * Wait for all URBs to the endpoint to be completed, then delete the
- * qset.
- */
-static void whc_endpoint_disable(struct usb_hcd *usb_hcd,
-                                struct usb_host_endpoint *ep)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       struct whc_qset *qset;
-
-       qset = ep->hcpriv;
-       if (qset) {
-               ep->hcpriv = NULL;
-               if (usb_endpoint_xfer_bulk(&ep->desc)
-                   || usb_endpoint_xfer_control(&ep->desc))
-                       asl_qset_delete(whc, qset);
-               else
-                       pzl_qset_delete(whc, qset);
-       }
-}
-
-static void whc_endpoint_reset(struct usb_hcd *usb_hcd,
-                              struct usb_host_endpoint *ep)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       struct whc_qset *qset;
-       unsigned long flags;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       qset = ep->hcpriv;
-       if (qset) {
-               qset->remove = 1;
-               qset->reset = 1;
-
-               if (usb_endpoint_xfer_bulk(&ep->desc)
-                   || usb_endpoint_xfer_control(&ep->desc))
-                       queue_work(whc->workqueue, &whc->async_work);
-               else
-                       queue_work(whc->workqueue, &whc->periodic_work);
-       }
-
-       spin_unlock_irqrestore(&whc->lock, flags);
-}
-
-
-static const struct hc_driver whc_hc_driver = {
-       .description = "whci-hcd",
-       .product_desc = "Wireless host controller",
-       .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd),
-       .irq = whc_int_handler,
-       .flags = HCD_USB2,
-
-       .reset = whc_reset,
-       .start = whc_start,
-       .stop = whc_stop,
-       .get_frame_number = whc_get_frame_number,
-       .urb_enqueue = whc_urb_enqueue,
-       .urb_dequeue = whc_urb_dequeue,
-       .endpoint_disable = whc_endpoint_disable,
-       .endpoint_reset = whc_endpoint_reset,
-
-       .hub_status_data = wusbhc_rh_status_data,
-       .hub_control = wusbhc_rh_control,
-       .start_port_reset = wusbhc_rh_start_port_reset,
-};
-
-static int whc_probe(struct umc_dev *umc)
-{
-       int ret;
-       struct usb_hcd *usb_hcd;
-       struct wusbhc *wusbhc;
-       struct whc *whc;
-       struct device *dev = &umc->dev;
-
-       usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci");
-       if (usb_hcd == NULL) {
-               dev_err(dev, "unable to create hcd\n");
-               return -ENOMEM;
-       }
-
-       usb_hcd->wireless = 1;
-       usb_hcd->self.sg_tablesize = 2048; /* somewhat arbitrary */
-
-       wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       whc = wusbhc_to_whc(wusbhc);
-       whc->umc = umc;
-
-       ret = whc_init(whc);
-       if (ret)
-               goto error_whc_init;
-
-       wusbhc->dev = dev;
-       wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent);
-       if (!wusbhc->uwb_rc) {
-               ret = -ENODEV;
-               dev_err(dev, "cannot get radio controller\n");
-               goto error_uwb_rc;
-       }
-
-       if (whc->n_devices > USB_MAXCHILDREN) {
-               dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n",
-                        whc->n_devices);
-               wusbhc->ports_max = USB_MAXCHILDREN;
-       } else
-               wusbhc->ports_max = whc->n_devices;
-       wusbhc->mmcies_max      = whc->n_mmc_ies;
-       wusbhc->start           = whc_wusbhc_start;
-       wusbhc->stop            = whc_wusbhc_stop;
-       wusbhc->mmcie_add       = whc_mmcie_add;
-       wusbhc->mmcie_rm        = whc_mmcie_rm;
-       wusbhc->dev_info_set    = whc_dev_info_set;
-       wusbhc->bwa_set         = whc_bwa_set;
-       wusbhc->set_num_dnts    = whc_set_num_dnts;
-       wusbhc->set_ptk         = whc_set_ptk;
-       wusbhc->set_gtk         = whc_set_gtk;
-
-       ret = wusbhc_create(wusbhc);
-       if (ret)
-               goto error_wusbhc_create;
-
-       ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED);
-       if (ret) {
-               dev_err(dev, "cannot add HCD: %d\n", ret);
-               goto error_usb_add_hcd;
-       }
-       device_wakeup_enable(usb_hcd->self.controller);
-
-       ret = wusbhc_b_create(wusbhc);
-       if (ret) {
-               dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret);
-               goto error_wusbhc_b_create;
-       }
-
-       whc_dbg_init(whc);
-
-       return 0;
-
-error_wusbhc_b_create:
-       usb_remove_hcd(usb_hcd);
-error_usb_add_hcd:
-       wusbhc_destroy(wusbhc);
-error_wusbhc_create:
-       uwb_rc_put(wusbhc->uwb_rc);
-error_uwb_rc:
-       whc_clean_up(whc);
-error_whc_init:
-       usb_put_hcd(usb_hcd);
-       return ret;
-}
-
-
-static void whc_remove(struct umc_dev *umc)
-{
-       struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev);
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-
-       if (usb_hcd) {
-               whc_dbg_clean_up(whc);
-               wusbhc_b_destroy(wusbhc);
-               usb_remove_hcd(usb_hcd);
-               wusbhc_destroy(wusbhc);
-               uwb_rc_put(wusbhc->uwb_rc);
-               whc_clean_up(whc);
-               usb_put_hcd(usb_hcd);
-       }
-}
-
-static struct umc_driver whci_hc_driver = {
-       .name =         "whci-hcd",
-       .cap_id =       UMC_CAP_ID_WHCI_WUSB_HC,
-       .probe =        whc_probe,
-       .remove =       whc_remove,
-};
-
-static int __init whci_hc_driver_init(void)
-{
-       return umc_driver_register(&whci_hc_driver);
-}
-module_init(whci_hc_driver_init);
-
-static void __exit whci_hc_driver_exit(void)
-{
-       umc_driver_unregister(&whci_hc_driver);
-}
-module_exit(whci_hc_driver_exit);
-
-/* PCI device ID's that we handle (so it gets loaded) */
-static struct pci_device_id __used whci_hcd_id_table[] = {
-       { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
-       { /* empty last entry */ }
-};
-MODULE_DEVICE_TABLE(pci, whci_hcd_id_table);
-
-MODULE_DESCRIPTION("WHCI Wireless USB host controller driver");
-MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/whci/hw.c b/drivers/usb/host/whci/hw.c
deleted file mode 100644 (file)
index 22b3b7f..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) hardware access helpers.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/dma-mapping.h>
-#include <linux/uwb/umc.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val)
-{
-       unsigned long flags;
-       u32 cmd;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       cmd = le_readl(whc->base + WUSBCMD);
-       cmd = (cmd & ~mask) | val;
-       le_writel(cmd, whc->base + WUSBCMD);
-
-       spin_unlock_irqrestore(&whc->lock, flags);
-}
-
-/**
- * whc_do_gencmd - start a generic command via the WUSBGENCMDSTS register
- * @whc:    the WHCI HC
- * @cmd:    command to start.
- * @params: parameters for the command (the WUSBGENCMDPARAMS register value).
- * @addr:   pointer to any data for the command (may be NULL).
- * @len:    length of the data (if any).
- */
-int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len)
-{
-       unsigned long flags;
-       dma_addr_t dma_addr;
-       int t;
-       int ret = 0;
-
-       mutex_lock(&whc->mutex);
-
-       /* Wait for previous command to complete. */
-       t = wait_event_timeout(whc->cmd_wq,
-                              (le_readl(whc->base + WUSBGENCMDSTS) & WUSBGENCMDSTS_ACTIVE) == 0,
-                              WHC_GENCMD_TIMEOUT_MS);
-       if (t == 0) {
-               dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n",
-                       le_readl(whc->base + WUSBGENCMDSTS),
-                       le_readl(whc->base + WUSBGENCMDPARAMS));
-               ret = -ETIMEDOUT;
-               goto out;
-       }
-
-       if (addr) {
-               memcpy(whc->gen_cmd_buf, addr, len);
-               dma_addr = whc->gen_cmd_buf_dma;
-       } else
-               dma_addr = 0;
-
-       /* Poke registers to start cmd. */
-       spin_lock_irqsave(&whc->lock, flags);
-
-       le_writel(params, whc->base + WUSBGENCMDPARAMS);
-       le_writeq(dma_addr, whc->base + WUSBGENADDR);
-
-       le_writel(WUSBGENCMDSTS_ACTIVE | WUSBGENCMDSTS_IOC | cmd,
-                 whc->base + WUSBGENCMDSTS);
-
-       spin_unlock_irqrestore(&whc->lock, flags);
-out:
-       mutex_unlock(&whc->mutex);
-
-       return ret;
-}
-
-/**
- * whc_hw_error - recover from a hardware error
- * @whc:    the WHCI HC that broke.
- * @reason: a description of the failure.
- *
- * Recover from broken hardware with a full reset.
- */
-void whc_hw_error(struct whc *whc, const char *reason)
-{
-       struct wusbhc *wusbhc = &whc->wusbhc;
-
-       dev_err(&whc->umc->dev, "hardware error: %s\n", reason);
-       wusbhc_reset_all(wusbhc);
-}
diff --git a/drivers/usb/host/whci/init.c b/drivers/usb/host/whci/init.c
deleted file mode 100644 (file)
index 8241697..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) initialization.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/dma-mapping.h>
-#include <linux/uwb/umc.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-/*
- * Reset the host controller.
- */
-static void whc_hw_reset(struct whc *whc)
-{
-       le_writel(WUSBCMD_WHCRESET, whc->base + WUSBCMD);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBCMD, WUSBCMD_WHCRESET, 0,
-                     100, "reset");
-}
-
-static void whc_hw_init_di_buf(struct whc *whc)
-{
-       int d;
-
-       /* Disable all entries in the Device Information buffer. */
-       for (d = 0; d < whc->n_devices; d++)
-               whc->di_buf[d].addr_sec_info = WHC_DI_DISABLE;
-
-       le_writeq(whc->di_buf_dma, whc->base + WUSBDEVICEINFOADDR);
-}
-
-static void whc_hw_init_dn_buf(struct whc *whc)
-{
-       /* Clear the Device Notification buffer to ensure the V (valid)
-        * bits are clear.  */
-       memset(whc->dn_buf, 0, 4096);
-
-       le_writeq(whc->dn_buf_dma, whc->base + WUSBDNTSBUFADDR);
-}
-
-int whc_init(struct whc *whc)
-{
-       u32 whcsparams;
-       int ret, i;
-       resource_size_t start, len;
-
-       spin_lock_init(&whc->lock);
-       mutex_init(&whc->mutex);
-       init_waitqueue_head(&whc->cmd_wq);
-       init_waitqueue_head(&whc->async_list_wq);
-       init_waitqueue_head(&whc->periodic_list_wq);
-       whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0);
-       if (whc->workqueue == NULL) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       INIT_WORK(&whc->dn_work, whc_dn_work);
-
-       INIT_WORK(&whc->async_work, scan_async_work);
-       INIT_LIST_HEAD(&whc->async_list);
-       INIT_LIST_HEAD(&whc->async_removed_list);
-
-       INIT_WORK(&whc->periodic_work, scan_periodic_work);
-       for (i = 0; i < 5; i++)
-               INIT_LIST_HEAD(&whc->periodic_list[i]);
-       INIT_LIST_HEAD(&whc->periodic_removed_list);
-
-       /* Map HC registers. */
-       start = whc->umc->resource.start;
-       len   = whc->umc->resource.end - start + 1;
-       if (!request_mem_region(start, len, "whci-hc")) {
-               dev_err(&whc->umc->dev, "can't request HC region\n");
-               ret = -EBUSY;
-               goto error;
-       }
-       whc->base_phys = start;
-       whc->base = ioremap(start, len);
-       if (!whc->base) {
-               dev_err(&whc->umc->dev, "ioremap\n");
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       whc_hw_reset(whc);
-
-       /* Read maximum number of devices, keys and MMC IEs. */
-       whcsparams = le_readl(whc->base + WHCSPARAMS);
-       whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams);
-       whc->n_keys    = WHCSPARAMS_TO_N_KEYS(whcsparams);
-       whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams);
-
-       dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n",
-               whc->n_devices, whc->n_keys, whc->n_mmc_ies);
-
-       whc->qset_pool = dma_pool_create("qset", &whc->umc->dev,
-                                        sizeof(struct whc_qset), 64, 0);
-       if (whc->qset_pool == NULL) {
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       ret = asl_init(whc);
-       if (ret < 0)
-               goto error;
-       ret = pzl_init(whc);
-       if (ret < 0)
-               goto error;
-
-       /* Allocate and initialize a buffer for generic commands, the
-          Device Information buffer, and the Device Notification
-          buffer. */
-
-       whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
-                                             &whc->gen_cmd_buf_dma, GFP_KERNEL);
-       if (whc->gen_cmd_buf == NULL) {
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       whc->dn_buf = dma_alloc_coherent(&whc->umc->dev,
-                                        sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
-                                        &whc->dn_buf_dma, GFP_KERNEL);
-       if (!whc->dn_buf) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       whc_hw_init_dn_buf(whc);
-
-       whc->di_buf = dma_alloc_coherent(&whc->umc->dev,
-                                        sizeof(struct di_buf_entry) * whc->n_devices,
-                                        &whc->di_buf_dma, GFP_KERNEL);
-       if (!whc->di_buf) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       whc_hw_init_di_buf(whc);
-
-       return 0;
-
-error:
-       whc_clean_up(whc);
-       return ret;
-}
-
-void whc_clean_up(struct whc *whc)
-{
-       resource_size_t len;
-
-       if (whc->di_buf)
-               dma_free_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices,
-                                 whc->di_buf, whc->di_buf_dma);
-       if (whc->dn_buf)
-               dma_free_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES,
-                                 whc->dn_buf, whc->dn_buf_dma);
-       if (whc->gen_cmd_buf)
-               dma_free_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN,
-                                 whc->gen_cmd_buf, whc->gen_cmd_buf_dma);
-
-       pzl_clean_up(whc);
-       asl_clean_up(whc);
-
-       dma_pool_destroy(whc->qset_pool);
-
-       len   = resource_size(&whc->umc->resource);
-       if (whc->base)
-               iounmap(whc->base);
-       if (whc->base_phys)
-               release_mem_region(whc->base_phys, len);
-
-       if (whc->workqueue)
-               destroy_workqueue(whc->workqueue);
-}
diff --git a/drivers/usb/host/whci/int.c b/drivers/usb/host/whci/int.c
deleted file mode 100644 (file)
index 7e4ad1b..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) interrupt handling.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/uwb/umc.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-static void transfer_done(struct whc *whc)
-{
-       queue_work(whc->workqueue, &whc->async_work);
-       queue_work(whc->workqueue, &whc->periodic_work);
-}
-
-irqreturn_t whc_int_handler(struct usb_hcd *hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd);
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u32 sts;
-
-       sts = le_readl(whc->base + WUSBSTS);
-       if (!(sts & WUSBSTS_INT_MASK))
-               return IRQ_NONE;
-       le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS);
-
-       if (sts & WUSBSTS_GEN_CMD_DONE)
-               wake_up(&whc->cmd_wq);
-
-       if (sts & WUSBSTS_HOST_ERR)
-               dev_err(&whc->umc->dev, "FIXME: host system error\n");
-
-       if (sts & WUSBSTS_ASYNC_SCHED_SYNCED)
-               wake_up(&whc->async_list_wq);
-
-       if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED)
-               wake_up(&whc->periodic_list_wq);
-
-       if (sts & WUSBSTS_DNTS_INT)
-               queue_work(whc->workqueue, &whc->dn_work);
-
-       /*
-        * A transfer completed (see [WHCI] section 4.7.1.2 for when
-        * this occurs).
-        */
-       if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT))
-               transfer_done(whc);
-
-       return IRQ_HANDLED;
-}
-
-static int process_dn_buf(struct whc *whc)
-{
-       struct wusbhc *wusbhc = &whc->wusbhc;
-       struct dn_buf_entry *dn;
-       int processed = 0;
-
-       for (dn = whc->dn_buf; dn < whc->dn_buf + WHC_N_DN_ENTRIES; dn++) {
-               if (dn->status & WHC_DN_STATUS_VALID) {
-                       wusbhc_handle_dn(wusbhc, dn->src_addr,
-                                        (struct wusb_dn_hdr *)dn->dn_data,
-                                        dn->msg_size);
-                       dn->status &= ~WHC_DN_STATUS_VALID;
-                       processed++;
-               }
-       }
-       return processed;
-}
-
-void whc_dn_work(struct work_struct *work)
-{
-       struct whc *whc = container_of(work, struct whc, dn_work);
-       int processed;
-
-       do {
-               processed = process_dn_buf(whc);
-       } while (processed);
-}
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c
deleted file mode 100644 (file)
index ef52aeb..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) periodic schedule management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/dma-mapping.h>
-#include <linux/uwb/umc.h>
-#include <linux/usb.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-static void update_pzl_pointers(struct whc *whc, int period, u64 addr)
-{
-       switch (period) {
-       case 0:
-               whc_qset_set_link_ptr(&whc->pz_list[0], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[2], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[4], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[6], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[8], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[10], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[12], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[14], addr);
-               break;
-       case 1:
-               whc_qset_set_link_ptr(&whc->pz_list[1], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[5], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[9], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[13], addr);
-               break;
-       case 2:
-               whc_qset_set_link_ptr(&whc->pz_list[3], addr);
-               whc_qset_set_link_ptr(&whc->pz_list[11], addr);
-               break;
-       case 3:
-               whc_qset_set_link_ptr(&whc->pz_list[7], addr);
-               break;
-       case 4:
-               whc_qset_set_link_ptr(&whc->pz_list[15], addr);
-               break;
-       }
-}
-
-/*
- * Return the 'period' to use for this qset.  The minimum interval for
- * the endpoint is used so whatever urbs are submitted the device is
- * polled often enough.
- */
-static int qset_get_period(struct whc *whc, struct whc_qset *qset)
-{
-       uint8_t bInterval = qset->ep->desc.bInterval;
-
-       if (bInterval < 6)
-               bInterval = 6;
-       if (bInterval > 10)
-               bInterval = 10;
-       return bInterval - 6;
-}
-
-static void qset_insert_in_sw_list(struct whc *whc, struct whc_qset *qset)
-{
-       int period;
-
-       period = qset_get_period(whc, qset);
-
-       qset_clear(whc, qset);
-       list_move(&qset->list_node, &whc->periodic_list[period]);
-       qset->in_sw_list = true;
-}
-
-static void pzl_qset_remove(struct whc *whc, struct whc_qset *qset)
-{
-       list_move(&qset->list_node, &whc->periodic_removed_list);
-       qset->in_hw_list = false;
-       qset->in_sw_list = false;
-}
-
-/**
- * pzl_process_qset - process any recently inactivated or halted qTDs
- * in a qset.
- *
- * After inactive qTDs are removed, new qTDs can be added if the
- * urb queue still contains URBs.
- *
- * Returns the schedule updates required.
- */
-static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
-{
-       enum whc_update update = 0;
-       uint32_t status = 0;
-
-       while (qset->ntds) {
-               struct whc_qtd *td;
-
-               td = &qset->qtd[qset->td_start];
-               status = le32_to_cpu(td->status);
-
-               /*
-                * Nothing to do with a still active qTD.
-                */
-               if (status & QTD_STS_ACTIVE)
-                       break;
-
-               if (status & QTD_STS_HALTED) {
-                       /* Ug, an error. */
-                       process_halted_qtd(whc, qset, td);
-                       /* A halted qTD always triggers an update
-                          because the qset was either removed or
-                          reactivated. */
-                       update |= WHC_UPDATE_UPDATED;
-                       goto done;
-               }
-
-               /* Mmm, a completed qTD. */
-               process_inactive_qtd(whc, qset, td);
-       }
-
-       if (!qset->remove)
-               update |= qset_add_qtds(whc, qset);
-
-done:
-       /*
-        * If there are no qTDs in this qset, remove it from the PZL.
-        */
-       if (qset->remove && qset->ntds == 0) {
-               pzl_qset_remove(whc, qset);
-               update |= WHC_UPDATE_REMOVED;
-       }
-
-       return update;
-}
-
-/**
- * pzl_start - start the periodic schedule
- * @whc: the WHCI host controller
- *
- * The PZL must be valid (e.g., all entries in the list should have
- * the T bit set).
- */
-void pzl_start(struct whc *whc)
-{
-       le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
-
-       whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, WUSBCMD_PERIODIC_EN);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
-                     WUSBSTS_PERIODIC_SCHED, WUSBSTS_PERIODIC_SCHED,
-                     1000, "start PZL");
-}
-
-/**
- * pzl_stop - stop the periodic schedule
- * @whc: the WHCI host controller
- */
-void pzl_stop(struct whc *whc)
-{
-       whc_write_wusbcmd(whc, WUSBCMD_PERIODIC_EN, 0);
-       whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
-                     WUSBSTS_PERIODIC_SCHED, 0,
-                     1000, "stop PZL");
-}
-
-/**
- * pzl_update - request a PZL update and wait for the hardware to be synced
- * @whc: the WHCI HC
- * @wusbcmd: WUSBCMD value to start the update.
- *
- * If the WUSB HC is inactive (i.e., the PZL is stopped) then the
- * update must be skipped as the hardware may not respond to update
- * requests.
- */
-void pzl_update(struct whc *whc, uint32_t wusbcmd)
-{
-       struct wusbhc *wusbhc = &whc->wusbhc;
-       long t;
-
-       mutex_lock(&wusbhc->mutex);
-       if (wusbhc->active) {
-               whc_write_wusbcmd(whc, wusbcmd, wusbcmd);
-               t = wait_event_timeout(
-                       whc->periodic_list_wq,
-                       (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0,
-                       msecs_to_jiffies(1000));
-               if (t == 0)
-                       whc_hw_error(whc, "PZL update timeout");
-       }
-       mutex_unlock(&wusbhc->mutex);
-}
-
-static void update_pzl_hw_view(struct whc *whc)
-{
-       struct whc_qset *qset, *t;
-       int period;
-       u64 tmp_qh = 0;
-
-       for (period = 0; period < 5; period++) {
-               list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
-                       whc_qset_set_link_ptr(&qset->qh.link, tmp_qh);
-                       tmp_qh = qset->qset_dma;
-                       qset->in_hw_list = true;
-               }
-               update_pzl_pointers(whc, period, tmp_qh);
-       }
-}
-
-/**
- * scan_periodic_work - scan the PZL for qsets to process.
- *
- * Process each qset in the PZL in turn and then signal the WHC that
- * the PZL has been updated.
- *
- * Then start, stop or update the periodic schedule as required.
- */
-void scan_periodic_work(struct work_struct *work)
-{
-       struct whc *whc = container_of(work, struct whc, periodic_work);
-       struct whc_qset *qset, *t;
-       enum whc_update update = 0;
-       int period;
-
-       spin_lock_irq(&whc->lock);
-
-       for (period = 4; period >= 0; period--) {
-               list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) {
-                       if (!qset->in_hw_list)
-                               update |= WHC_UPDATE_ADDED;
-                       update |= pzl_process_qset(whc, qset);
-               }
-       }
-
-       if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED))
-               update_pzl_hw_view(whc);
-
-       spin_unlock_irq(&whc->lock);
-
-       if (update) {
-               uint32_t wusbcmd = WUSBCMD_PERIODIC_UPDATED | WUSBCMD_PERIODIC_SYNCED_DB;
-               if (update & WHC_UPDATE_REMOVED)
-                       wusbcmd |= WUSBCMD_PERIODIC_QSET_RM;
-               pzl_update(whc, wusbcmd);
-       }
-
-       /*
-        * Now that the PZL is updated, complete the removal of any
-        * removed qsets.
-        *
-        * If the qset was to be reset, do so and reinsert it into the
-        * PZL if it has pending transfers.
-        */
-       spin_lock_irq(&whc->lock);
-
-       list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
-               qset_remove_complete(whc, qset);
-               if (qset->reset) {
-                       qset_reset(whc, qset);
-                       if (!list_empty(&qset->stds)) {
-                               qset_insert_in_sw_list(whc, qset);
-                               queue_work(whc->workqueue, &whc->periodic_work);
-                       }
-               }
-       }
-
-       spin_unlock_irq(&whc->lock);
-}
-
-/**
- * pzl_urb_enqueue - queue an URB onto the periodic list (PZL)
- * @whc: the WHCI host controller
- * @urb: the URB to enqueue
- * @mem_flags: flags for any memory allocations
- *
- * The qset for the endpoint is obtained and the urb queued on to it.
- *
- * Work is scheduled to update the hardware's view of the PZL.
- */
-int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
-{
-       struct whc_qset *qset;
-       int err;
-       unsigned long flags;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb);
-       if (err < 0) {
-               spin_unlock_irqrestore(&whc->lock, flags);
-               return err;
-       }
-
-       qset = get_qset(whc, urb, GFP_ATOMIC);
-       if (qset == NULL)
-               err = -ENOMEM;
-       else
-               err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
-       if (!err) {
-               if (!qset->in_sw_list && !qset->remove)
-                       qset_insert_in_sw_list(whc, qset);
-       } else
-               usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);
-
-       spin_unlock_irqrestore(&whc->lock, flags);
-
-       if (!err)
-               queue_work(whc->workqueue, &whc->periodic_work);
-
-       return err;
-}
-
-/**
- * pzl_urb_dequeue - remove an URB (qset) from the periodic list
- * @whc: the WHCI host controller
- * @urb: the URB to dequeue
- * @status: the current status of the URB
- *
- * URBs that do yet have qTDs can simply be removed from the software
- * queue, otherwise the qset must be removed so the qTDs can be safely
- * removed.
- */
-int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
-{
-       struct whc_urb *wurb = urb->hcpriv;
-       struct whc_qset *qset = wurb->qset;
-       struct whc_std *std, *t;
-       bool has_qtd = false;
-       int ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&whc->lock, flags);
-
-       ret = usb_hcd_check_unlink_urb(&whc->wusbhc.usb_hcd, urb, status);
-       if (ret < 0)
-               goto out;
-
-       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
-               if (std->urb == urb) {
-                       if (std->qtd)
-                               has_qtd = true;
-                       qset_free_std(whc, std);
-               } else
-                       std->qtd = NULL; /* so this std is re-added when the qset is */
-       }
-
-       if (has_qtd) {
-               pzl_qset_remove(whc, qset);
-               update_pzl_hw_view(whc);
-               wurb->status = status;
-               wurb->is_async = false;
-               queue_work(whc->workqueue, &wurb->dequeue_work);
-       } else
-               qset_remove_urb(whc, qset, urb, status);
-out:
-       spin_unlock_irqrestore(&whc->lock, flags);
-
-       return ret;
-}
-
-/**
- * pzl_qset_delete - delete a qset from the PZL
- */
-void pzl_qset_delete(struct whc *whc, struct whc_qset *qset)
-{
-       qset->remove = 1;
-       queue_work(whc->workqueue, &whc->periodic_work);
-       qset_delete(whc, qset);
-}
-
-/**
- * pzl_init - initialize the periodic zone list
- * @whc: the WHCI host controller
- */
-int pzl_init(struct whc *whc)
-{
-       int i;
-
-       whc->pz_list = dma_alloc_coherent(&whc->umc->dev, sizeof(u64) * 16,
-                                         &whc->pz_list_dma, GFP_KERNEL);
-       if (whc->pz_list == NULL)
-               return -ENOMEM;
-
-       /* Set T bit on all elements in PZL. */
-       for (i = 0; i < 16; i++)
-               whc->pz_list[i] = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
-
-       le_writeq(whc->pz_list_dma, whc->base + WUSBPERIODICLISTBASE);
-
-       return 0;
-}
-
-/**
- * pzl_clean_up - free PZL resources
- * @whc: the WHCI host controller
- *
- * The PZL is stopped and empty.
- */
-void pzl_clean_up(struct whc *whc)
-{
-       if (whc->pz_list)
-               dma_free_coherent(&whc->umc->dev,  sizeof(u64) * 16, whc->pz_list,
-                                 whc->pz_list_dma);
-}
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
deleted file mode 100644 (file)
index 925166a..0000000
+++ /dev/null
@@ -1,831 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) qset management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/uwb/umc.h>
-#include <linux/usb.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags)
-{
-       struct whc_qset *qset;
-       dma_addr_t dma;
-
-       qset = dma_pool_zalloc(whc->qset_pool, mem_flags, &dma);
-       if (qset == NULL)
-               return NULL;
-
-       qset->qset_dma = dma;
-       qset->whc = whc;
-
-       INIT_LIST_HEAD(&qset->list_node);
-       INIT_LIST_HEAD(&qset->stds);
-
-       return qset;
-}
-
-/**
- * qset_fill_qh - fill the static endpoint state in a qset's QHead
- * @qset: the qset whose QH needs initializing with static endpoint
- *        state
- * @urb:  an urb for a transfer to this endpoint
- */
-static void qset_fill_qh(struct whc *whc, struct whc_qset *qset, struct urb *urb)
-{
-       struct usb_device *usb_dev = urb->dev;
-       struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
-       struct usb_wireless_ep_comp_descriptor *epcd;
-       bool is_out;
-       uint8_t phy_rate;
-
-       is_out = usb_pipeout(urb->pipe);
-
-       qset->max_packet = le16_to_cpu(urb->ep->desc.wMaxPacketSize);
-
-       epcd = (struct usb_wireless_ep_comp_descriptor *)qset->ep->extra;
-       if (epcd) {
-               qset->max_seq = epcd->bMaxSequence;
-               qset->max_burst = epcd->bMaxBurst;
-       } else {
-               qset->max_seq = 2;
-               qset->max_burst = 1;
-       }
-
-       /*
-        * Initial PHY rate is 53.3 Mbit/s for control endpoints or
-        * the maximum supported by the device for other endpoints
-        * (unless limited by the user).
-        */
-       if (usb_pipecontrol(urb->pipe))
-               phy_rate = UWB_PHY_RATE_53;
-       else {
-               uint16_t phy_rates;
-
-               phy_rates = le16_to_cpu(wusb_dev->wusb_cap_descr->wPHYRates);
-               phy_rate = fls(phy_rates) - 1;
-               if (phy_rate > whc->wusbhc.phy_rate)
-                       phy_rate = whc->wusbhc.phy_rate;
-       }
-
-       qset->qh.info1 = cpu_to_le32(
-               QH_INFO1_EP(usb_pipeendpoint(urb->pipe))
-               | (is_out ? QH_INFO1_DIR_OUT : QH_INFO1_DIR_IN)
-               | usb_pipe_to_qh_type(urb->pipe)
-               | QH_INFO1_DEV_INFO_IDX(wusb_port_no_to_idx(usb_dev->portnum))
-               | QH_INFO1_MAX_PKT_LEN(qset->max_packet)
-               );
-       qset->qh.info2 = cpu_to_le32(
-               QH_INFO2_BURST(qset->max_burst)
-               | QH_INFO2_DBP(0)
-               | QH_INFO2_MAX_COUNT(3)
-               | QH_INFO2_MAX_RETRY(3)
-               | QH_INFO2_MAX_SEQ(qset->max_seq - 1)
-               );
-       /* FIXME: where can we obtain these Tx parameters from?  Why
-        * doesn't the chip know what Tx power to use? It knows the Rx
-        * strength and can presumably guess the Tx power required
-        * from that? */
-       qset->qh.info3 = cpu_to_le32(
-               QH_INFO3_TX_RATE(phy_rate)
-               | QH_INFO3_TX_PWR(0) /* 0 == max power */
-               );
-
-       qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
-}
-
-/**
- * qset_clear - clear fields in a qset so it may be reinserted into a
- * schedule.
- *
- * The sequence number and current window are not cleared (see
- * qset_reset()).
- */
-void qset_clear(struct whc *whc, struct whc_qset *qset)
-{
-       qset->td_start = qset->td_end = qset->ntds = 0;
-
-       qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T);
-       qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
-       qset->qh.err_count = 0;
-       qset->qh.scratch[0] = 0;
-       qset->qh.scratch[1] = 0;
-       qset->qh.scratch[2] = 0;
-
-       memset(&qset->qh.overlay, 0, sizeof(qset->qh.overlay));
-
-       init_completion(&qset->remove_complete);
-}
-
-/**
- * qset_reset - reset endpoint state in a qset.
- *
- * Clears the sequence number and current window.  This qset must not
- * be in the ASL or PZL.
- */
-void qset_reset(struct whc *whc, struct whc_qset *qset)
-{
-       qset->reset = 0;
-
-       qset->qh.status &= ~QH_STATUS_SEQ_MASK;
-       qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
-}
-
-/**
- * get_qset - get the qset for an async endpoint
- *
- * A new qset is created if one does not already exist.
- */
-struct whc_qset *get_qset(struct whc *whc, struct urb *urb,
-                                gfp_t mem_flags)
-{
-       struct whc_qset *qset;
-
-       qset = urb->ep->hcpriv;
-       if (qset == NULL) {
-               qset = qset_alloc(whc, mem_flags);
-               if (qset == NULL)
-                       return NULL;
-
-               qset->ep = urb->ep;
-               urb->ep->hcpriv = qset;
-               qset_fill_qh(whc, qset, urb);
-       }
-       return qset;
-}
-
-void qset_remove_complete(struct whc *whc, struct whc_qset *qset)
-{
-       qset->remove = 0;
-       list_del_init(&qset->list_node);
-       complete(&qset->remove_complete);
-}
-
-/**
- * qset_add_qtds - add qTDs for an URB to a qset
- *
- * Returns true if the list (ASL/PZL) must be updated because (for a
- * WHCI 0.95 controller) an activated qTD was pointed to be iCur.
- */
-enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset)
-{
-       struct whc_std *std;
-       enum whc_update update = 0;
-
-       list_for_each_entry(std, &qset->stds, list_node) {
-               struct whc_qtd *qtd;
-               uint32_t status;
-
-               if (qset->ntds >= WHCI_QSET_TD_MAX
-                   || (qset->pause_after_urb && std->urb != qset->pause_after_urb))
-                       break;
-
-               if (std->qtd)
-                       continue; /* already has a qTD */
-
-               qtd = std->qtd = &qset->qtd[qset->td_end];
-
-               /* Fill in setup bytes for control transfers. */
-               if (usb_pipecontrol(std->urb->pipe))
-                       memcpy(qtd->setup, std->urb->setup_packet, 8);
-
-               status = QTD_STS_ACTIVE | QTD_STS_LEN(std->len);
-
-               if (whc_std_last(std) && usb_pipeout(std->urb->pipe))
-                       status |= QTD_STS_LAST_PKT;
-
-               /*
-                * For an IN transfer the iAlt field should be set so
-                * the h/w will automatically advance to the next
-                * transfer. However, if there are 8 or more TDs
-                * remaining in this transfer then iAlt cannot be set
-                * as it could point to somewhere in this transfer.
-                */
-               if (std->ntds_remaining < WHCI_QSET_TD_MAX) {
-                       int ialt;
-                       ialt = (qset->td_end + std->ntds_remaining) % WHCI_QSET_TD_MAX;
-                       status |= QTD_STS_IALT(ialt);
-               } else if (usb_pipein(std->urb->pipe))
-                       qset->pause_after_urb = std->urb;
-
-               if (std->num_pointers)
-                       qtd->options = cpu_to_le32(QTD_OPT_IOC);
-               else
-                       qtd->options = cpu_to_le32(QTD_OPT_IOC | QTD_OPT_SMALL);
-               qtd->page_list_ptr = cpu_to_le64(std->dma_addr);
-
-               qtd->status = cpu_to_le32(status);
-
-               if (QH_STATUS_TO_ICUR(qset->qh.status) == qset->td_end)
-                       update = WHC_UPDATE_UPDATED;
-
-               if (++qset->td_end >= WHCI_QSET_TD_MAX)
-                       qset->td_end = 0;
-               qset->ntds++;
-       }
-
-       return update;
-}
-
-/**
- * qset_remove_qtd - remove the first qTD from a qset.
- *
- * The qTD might be still active (if it's part of a IN URB that
- * resulted in a short read) so ensure it's deactivated.
- */
-static void qset_remove_qtd(struct whc *whc, struct whc_qset *qset)
-{
-       qset->qtd[qset->td_start].status = 0;
-
-       if (++qset->td_start >= WHCI_QSET_TD_MAX)
-               qset->td_start = 0;
-       qset->ntds--;
-}
-
-static void qset_copy_bounce_to_sg(struct whc *whc, struct whc_std *std)
-{
-       struct scatterlist *sg;
-       void *bounce;
-       size_t remaining, offset;
-
-       bounce = std->bounce_buf;
-       remaining = std->len;
-
-       sg = std->bounce_sg;
-       offset = std->bounce_offset;
-
-       while (remaining) {
-               size_t len;
-
-               len = min(sg->length - offset, remaining);
-               memcpy(sg_virt(sg) + offset, bounce, len);
-
-               bounce += len;
-               remaining -= len;
-
-               offset += len;
-               if (offset >= sg->length) {
-                       sg = sg_next(sg);
-                       offset = 0;
-               }
-       }
-
-}
-
-/**
- * qset_free_std - remove an sTD and free it.
- * @whc: the WHCI host controller
- * @std: the sTD to remove and free.
- */
-void qset_free_std(struct whc *whc, struct whc_std *std)
-{
-       list_del(&std->list_node);
-       if (std->bounce_buf) {
-               bool is_out = usb_pipeout(std->urb->pipe);
-               dma_addr_t dma_addr;
-
-               if (std->num_pointers)
-                       dma_addr = le64_to_cpu(std->pl_virt[0].buf_ptr);
-               else
-                       dma_addr = std->dma_addr;
-
-               dma_unmap_single(whc->wusbhc.dev, dma_addr,
-                                std->len, is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               if (!is_out)
-                       qset_copy_bounce_to_sg(whc, std);
-               kfree(std->bounce_buf);
-       }
-       if (std->pl_virt) {
-               if (!dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
-                       dma_unmap_single(whc->wusbhc.dev, std->dma_addr,
-                                        std->num_pointers * sizeof(struct whc_page_list_entry),
-                                        DMA_TO_DEVICE);
-               kfree(std->pl_virt);
-               std->pl_virt = NULL;
-       }
-       kfree(std);
-}
-
-/**
- * qset_remove_qtds - remove an URB's qTDs (and sTDs).
- */
-static void qset_remove_qtds(struct whc *whc, struct whc_qset *qset,
-                            struct urb *urb)
-{
-       struct whc_std *std, *t;
-
-       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
-               if (std->urb != urb)
-                       break;
-               if (std->qtd != NULL)
-                       qset_remove_qtd(whc, qset);
-               qset_free_std(whc, std);
-       }
-}
-
-/**
- * qset_free_stds - free any remaining sTDs for an URB.
- */
-static void qset_free_stds(struct whc_qset *qset, struct urb *urb)
-{
-       struct whc_std *std, *t;
-
-       list_for_each_entry_safe(std, t, &qset->stds, list_node) {
-               if (std->urb == urb)
-                       qset_free_std(qset->whc, std);
-       }
-}
-
-static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_flags)
-{
-       dma_addr_t dma_addr = std->dma_addr;
-       dma_addr_t sp, ep;
-       size_t pl_len;
-       int p;
-
-       /* Short buffers don't need a page list. */
-       if (std->len <= WHCI_PAGE_SIZE) {
-               std->num_pointers = 0;
-               return 0;
-       }
-
-       sp = dma_addr & ~(WHCI_PAGE_SIZE-1);
-       ep = dma_addr + std->len;
-       std->num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
-
-       pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
-       std->pl_virt = kmalloc(pl_len, mem_flags);
-       if (std->pl_virt == NULL)
-               return -ENOMEM;
-       std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE);
-       if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) {
-               kfree(std->pl_virt);
-               return -EFAULT;
-       }
-
-       for (p = 0; p < std->num_pointers; p++) {
-               std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
-               dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
-       }
-
-       return 0;
-}
-
-/**
- * urb_dequeue_work - executes asl/pzl update and gives back the urb to the system.
- */
-static void urb_dequeue_work(struct work_struct *work)
-{
-       struct whc_urb *wurb = container_of(work, struct whc_urb, dequeue_work);
-       struct whc_qset *qset = wurb->qset;
-       struct whc *whc = qset->whc;
-       unsigned long flags;
-
-       if (wurb->is_async)
-               asl_update(whc, WUSBCMD_ASYNC_UPDATED
-                          | WUSBCMD_ASYNC_SYNCED_DB
-                          | WUSBCMD_ASYNC_QSET_RM);
-       else
-               pzl_update(whc, WUSBCMD_PERIODIC_UPDATED
-                          | WUSBCMD_PERIODIC_SYNCED_DB
-                          | WUSBCMD_PERIODIC_QSET_RM);
-
-       spin_lock_irqsave(&whc->lock, flags);
-       qset_remove_urb(whc, qset, wurb->urb, wurb->status);
-       spin_unlock_irqrestore(&whc->lock, flags);
-}
-
-static struct whc_std *qset_new_std(struct whc *whc, struct whc_qset *qset,
-                                   struct urb *urb, gfp_t mem_flags)
-{
-       struct whc_std *std;
-
-       std = kzalloc(sizeof(struct whc_std), mem_flags);
-       if (std == NULL)
-               return NULL;
-
-       std->urb = urb;
-       std->qtd = NULL;
-
-       INIT_LIST_HEAD(&std->list_node);
-       list_add_tail(&std->list_node, &qset->stds);
-
-       return std;
-}
-
-static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *urb,
-                          gfp_t mem_flags)
-{
-       size_t remaining;
-       struct scatterlist *sg;
-       int i;
-       int ntds = 0;
-       struct whc_std *std = NULL;
-       struct whc_page_list_entry *new_pl_virt;
-       dma_addr_t prev_end = 0;
-       size_t pl_len;
-       int p = 0;
-
-       remaining = urb->transfer_buffer_length;
-
-       for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
-               dma_addr_t dma_addr;
-               size_t dma_remaining;
-               dma_addr_t sp, ep;
-               int num_pointers;
-
-               if (remaining == 0) {
-                       break;
-               }
-
-               dma_addr = sg_dma_address(sg);
-               dma_remaining = min_t(size_t, sg_dma_len(sg), remaining);
-
-               while (dma_remaining) {
-                       size_t dma_len;
-
-                       /*
-                        * We can use the previous std (if it exists) provided that:
-                        * - the previous one ended on a page boundary.
-                        * - the current one begins on a page boundary.
-                        * - the previous one isn't full.
-                        *
-                        * If a new std is needed but the previous one
-                        * was not a whole number of packets then this
-                        * sg list cannot be mapped onto multiple
-                        * qTDs.  Return an error and let the caller
-                        * sort it out.
-                        */
-                       if (!std
-                           || (prev_end & (WHCI_PAGE_SIZE-1))
-                           || (dma_addr & (WHCI_PAGE_SIZE-1))
-                           || std->len + WHCI_PAGE_SIZE > QTD_MAX_XFER_SIZE) {
-                               if (std && std->len % qset->max_packet != 0)
-                                       return -EINVAL;
-                               std = qset_new_std(whc, qset, urb, mem_flags);
-                               if (std == NULL) {
-                                       return -ENOMEM;
-                               }
-                               ntds++;
-                               p = 0;
-                       }
-
-                       dma_len = dma_remaining;
-
-                       /*
-                        * If the remainder of this element doesn't
-                        * fit in a single qTD, limit the qTD to a
-                        * whole number of packets.  This allows the
-                        * remainder to go into the next qTD.
-                        */
-                       if (std->len + dma_len > QTD_MAX_XFER_SIZE) {
-                               dma_len = (QTD_MAX_XFER_SIZE / qset->max_packet)
-                                       * qset->max_packet - std->len;
-                       }
-
-                       std->len += dma_len;
-                       std->ntds_remaining = -1; /* filled in later */
-
-                       sp = dma_addr & ~(WHCI_PAGE_SIZE-1);
-                       ep = dma_addr + dma_len;
-                       num_pointers = DIV_ROUND_UP(ep - sp, WHCI_PAGE_SIZE);
-                       std->num_pointers += num_pointers;
-
-                       pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
-
-                       new_pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
-                       if (new_pl_virt == NULL) {
-                               kfree(std->pl_virt);
-                               std->pl_virt = NULL;
-                               return -ENOMEM;
-                       }
-                       std->pl_virt = new_pl_virt;
-
-                       for (;p < std->num_pointers; p++) {
-                               std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
-                               dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
-                       }
-
-                       prev_end = dma_addr = ep;
-                       dma_remaining -= dma_len;
-                       remaining -= dma_len;
-               }
-       }
-
-       /* Now the number of stds is know, go back and fill in
-          std->ntds_remaining. */
-       list_for_each_entry(std, &qset->stds, list_node) {
-               if (std->ntds_remaining == -1) {
-                       pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
-                       std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt,
-                                                      pl_len, DMA_TO_DEVICE);
-                       if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr))
-                               return -EFAULT;
-                       std->ntds_remaining = ntds--;
-               }
-       }
-       return 0;
-}
-
-/**
- * qset_add_urb_sg_linearize - add an urb with sg list, copying the data
- *
- * If the URB contains an sg list whose elements cannot be directly
- * mapped to qTDs then the data must be transferred via bounce
- * buffers.
- */
-static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,
-                                    struct urb *urb, gfp_t mem_flags)
-{
-       bool is_out = usb_pipeout(urb->pipe);
-       size_t max_std_len;
-       size_t remaining;
-       int ntds = 0;
-       struct whc_std *std = NULL;
-       void *bounce = NULL;
-       struct scatterlist *sg;
-       int i;
-
-       /* limit maximum bounce buffer to 16 * 3.5 KiB ~= 28 k */
-       max_std_len = qset->max_burst * qset->max_packet;
-
-       remaining = urb->transfer_buffer_length;
-
-       for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
-               size_t len;
-               size_t sg_remaining;
-               void *orig;
-
-               if (remaining == 0) {
-                       break;
-               }
-
-               sg_remaining = min_t(size_t, remaining, sg->length);
-               orig = sg_virt(sg);
-
-               while (sg_remaining) {
-                       if (!std || std->len == max_std_len) {
-                               std = qset_new_std(whc, qset, urb, mem_flags);
-                               if (std == NULL)
-                                       return -ENOMEM;
-                               std->bounce_buf = kmalloc(max_std_len, mem_flags);
-                               if (std->bounce_buf == NULL)
-                                       return -ENOMEM;
-                               std->bounce_sg = sg;
-                               std->bounce_offset = orig - sg_virt(sg);
-                               bounce = std->bounce_buf;
-                               ntds++;
-                       }
-
-                       len = min(sg_remaining, max_std_len - std->len);
-
-                       if (is_out)
-                               memcpy(bounce, orig, len);
-
-                       std->len += len;
-                       std->ntds_remaining = -1; /* filled in later */
-
-                       bounce += len;
-                       orig += len;
-                       sg_remaining -= len;
-                       remaining -= len;
-               }
-       }
-
-       /*
-        * For each of the new sTDs, map the bounce buffers, create
-        * page lists (if necessary), and fill in std->ntds_remaining.
-        */
-       list_for_each_entry(std, &qset->stds, list_node) {
-               if (std->ntds_remaining != -1)
-                       continue;
-
-               std->dma_addr = dma_map_single(&whc->umc->dev, std->bounce_buf, std->len,
-                                              is_out ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-               if (dma_mapping_error(&whc->umc->dev, std->dma_addr))
-                       return -EFAULT;
-
-               if (qset_fill_page_list(whc, std, mem_flags) < 0)
-                       return -ENOMEM;
-
-               std->ntds_remaining = ntds--;
-       }
-
-       return 0;
-}
-
-/**
- * qset_add_urb - add an urb to the qset's queue.
- *
- * The URB is chopped into sTDs, one for each qTD that will required.
- * At least one qTD (and sTD) is required even if the transfer has no
- * data (e.g., for some control transfers).
- */
-int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
-       gfp_t mem_flags)
-{
-       struct whc_urb *wurb;
-       int remaining = urb->transfer_buffer_length;
-       u64 transfer_dma = urb->transfer_dma;
-       int ntds_remaining;
-       int ret;
-
-       wurb = kzalloc(sizeof(struct whc_urb), mem_flags);
-       if (wurb == NULL)
-               goto err_no_mem;
-       urb->hcpriv = wurb;
-       wurb->qset = qset;
-       wurb->urb = urb;
-       INIT_WORK(&wurb->dequeue_work, urb_dequeue_work);
-
-       if (urb->num_sgs) {
-               ret = qset_add_urb_sg(whc, qset, urb, mem_flags);
-               if (ret == -EINVAL) {
-                       qset_free_stds(qset, urb);
-                       ret = qset_add_urb_sg_linearize(whc, qset, urb, mem_flags);
-               }
-               if (ret < 0)
-                       goto err_no_mem;
-               return 0;
-       }
-
-       ntds_remaining = DIV_ROUND_UP(remaining, QTD_MAX_XFER_SIZE);
-       if (ntds_remaining == 0)
-               ntds_remaining = 1;
-
-       while (ntds_remaining) {
-               struct whc_std *std;
-               size_t std_len;
-
-               std_len = remaining;
-               if (std_len > QTD_MAX_XFER_SIZE)
-                       std_len = QTD_MAX_XFER_SIZE;
-
-               std = qset_new_std(whc, qset, urb, mem_flags);
-               if (std == NULL)
-                       goto err_no_mem;
-
-               std->dma_addr = transfer_dma;
-               std->len = std_len;
-               std->ntds_remaining = ntds_remaining;
-
-               if (qset_fill_page_list(whc, std, mem_flags) < 0)
-                       goto err_no_mem;
-
-               ntds_remaining--;
-               remaining -= std_len;
-               transfer_dma += std_len;
-       }
-
-       return 0;
-
-err_no_mem:
-       qset_free_stds(qset, urb);
-       return -ENOMEM;
-}
-
-/**
- * qset_remove_urb - remove an URB from the urb queue.
- *
- * The URB is returned to the USB subsystem.
- */
-void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
-                           struct urb *urb, int status)
-{
-       struct wusbhc *wusbhc = &whc->wusbhc;
-       struct whc_urb *wurb = urb->hcpriv;
-
-       usb_hcd_unlink_urb_from_ep(&wusbhc->usb_hcd, urb);
-       /* Drop the lock as urb->complete() may enqueue another urb. */
-       spin_unlock(&whc->lock);
-       wusbhc_giveback_urb(wusbhc, urb, status);
-       spin_lock(&whc->lock);
-
-       kfree(wurb);
-}
-
-/**
- * get_urb_status_from_qtd - get the completed urb status from qTD status
- * @urb:    completed urb
- * @status: qTD status
- */
-static int get_urb_status_from_qtd(struct urb *urb, u32 status)
-{
-       if (status & QTD_STS_HALTED) {
-               if (status & QTD_STS_DBE)
-                       return usb_pipein(urb->pipe) ? -ENOSR : -ECOMM;
-               else if (status & QTD_STS_BABBLE)
-                       return -EOVERFLOW;
-               else if (status & QTD_STS_RCE)
-                       return -ETIME;
-               return -EPIPE;
-       }
-       if (usb_pipein(urb->pipe)
-           && (urb->transfer_flags & URB_SHORT_NOT_OK)
-           && urb->actual_length < urb->transfer_buffer_length)
-               return -EREMOTEIO;
-       return 0;
-}
-
-/**
- * process_inactive_qtd - process an inactive (but not halted) qTD.
- *
- * Update the urb with the transfer bytes from the qTD, if the urb is
- * completely transferred or (in the case of an IN only) the LPF is
- * set, then the transfer is complete and the urb should be returned
- * to the system.
- */
-void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
-                                struct whc_qtd *qtd)
-{
-       struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
-       struct urb *urb = std->urb;
-       uint32_t status;
-       bool complete;
-
-       status = le32_to_cpu(qtd->status);
-
-       urb->actual_length += std->len - QTD_STS_TO_LEN(status);
-
-       if (usb_pipein(urb->pipe) && (status & QTD_STS_LAST_PKT))
-               complete = true;
-       else
-               complete = whc_std_last(std);
-
-       qset_remove_qtd(whc, qset);
-       qset_free_std(whc, std);
-
-       /*
-        * Transfers for this URB are complete?  Then return it to the
-        * USB subsystem.
-        */
-       if (complete) {
-               qset_remove_qtds(whc, qset, urb);
-               qset_remove_urb(whc, qset, urb, get_urb_status_from_qtd(urb, status));
-
-               /*
-                * If iAlt isn't valid then the hardware didn't
-                * advance iCur. Adjust the start and end pointers to
-                * match iCur.
-                */
-               if (!(status & QTD_STS_IALT_VALID))
-                       qset->td_start = qset->td_end
-                               = QH_STATUS_TO_ICUR(le16_to_cpu(qset->qh.status));
-               qset->pause_after_urb = NULL;
-       }
-}
-
-/**
- * process_halted_qtd - process a qset with a halted qtd
- *
- * Remove all the qTDs for the failed URB and return the failed URB to
- * the USB subsystem.  Then remove all other qTDs so the qset can be
- * removed.
- *
- * FIXME: this is the point where rate adaptation can be done.  If a
- * transfer failed because it exceeded the maximum number of retries
- * then it could be reactivated with a slower rate without having to
- * remove the qset.
- */
-void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
-                              struct whc_qtd *qtd)
-{
-       struct whc_std *std = list_first_entry(&qset->stds, struct whc_std, list_node);
-       struct urb *urb = std->urb;
-       int urb_status;
-
-       urb_status = get_urb_status_from_qtd(urb, le32_to_cpu(qtd->status));
-
-       qset_remove_qtds(whc, qset, urb);
-       qset_remove_urb(whc, qset, urb, urb_status);
-
-       list_for_each_entry(std, &qset->stds, list_node) {
-               if (qset->ntds == 0)
-                       break;
-               qset_remove_qtd(whc, qset);
-               std->qtd = NULL;
-       }
-
-       qset->remove = 1;
-}
-
-void qset_free(struct whc *whc, struct whc_qset *qset)
-{
-       dma_pool_free(whc->qset_pool, qset, qset->qset_dma);
-}
-
-/**
- * qset_delete - wait for a qset to be unused, then free it.
- */
-void qset_delete(struct whc *whc, struct whc_qset *qset)
-{
-       wait_for_completion(&qset->remove_complete);
-       qset_free(whc, qset);
-}
diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h
deleted file mode 100644 (file)
index 1394769..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) private header.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#ifndef __WHCD_H
-#define __WHCD_H
-
-#include <linux/uwb/whci.h>
-#include <linux/uwb/umc.h>
-#include <linux/workqueue.h>
-
-#include "whci-hc.h"
-
-/* Generic command timeout. */
-#define WHC_GENCMD_TIMEOUT_MS 100
-
-struct whc_dbg;
-
-struct whc {
-       struct wusbhc wusbhc;
-       struct umc_dev *umc;
-
-       resource_size_t base_phys;
-       void __iomem *base;
-       int irq;
-
-       u8 n_devices;
-       u8 n_keys;
-       u8 n_mmc_ies;
-
-       u64 *pz_list;
-       struct dn_buf_entry *dn_buf;
-       struct di_buf_entry *di_buf;
-       dma_addr_t pz_list_dma;
-       dma_addr_t dn_buf_dma;
-       dma_addr_t di_buf_dma;
-
-       spinlock_t   lock;
-       struct mutex mutex;
-
-       void *            gen_cmd_buf;
-       dma_addr_t        gen_cmd_buf_dma;
-       wait_queue_head_t cmd_wq;
-
-       struct workqueue_struct *workqueue;
-       struct work_struct       dn_work;
-
-       struct dma_pool *qset_pool;
-
-       struct list_head async_list;
-       struct list_head async_removed_list;
-       wait_queue_head_t async_list_wq;
-       struct work_struct async_work;
-
-       struct list_head periodic_list[5];
-       struct list_head periodic_removed_list;
-       wait_queue_head_t periodic_list_wq;
-       struct work_struct periodic_work;
-
-       struct whc_dbg *dbg;
-};
-
-#define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc))
-
-/**
- * struct whc_std - a software TD.
- * @urb: the URB this sTD is for.
- * @offset: start of the URB's data for this TD.
- * @len: the length of data in the associated TD.
- * @ntds_remaining: number of TDs (starting from this one) in this transfer.
- *
- * @bounce_buf: a bounce buffer if the std was from an urb with a sg
- * list that could not be mapped to qTDs directly.
- * @bounce_sg: the first scatterlist element bounce_buf is for.
- * @bounce_offset: the offset into bounce_sg for the start of bounce_buf.
- *
- * Queued URBs may require more TDs than are available in a qset so we
- * use a list of these "software TDs" (sTDs) to hold per-TD data.
- */
-struct whc_std {
-       struct urb *urb;
-       size_t len;
-       int    ntds_remaining;
-       struct whc_qtd *qtd;
-
-       struct list_head list_node;
-       int num_pointers;
-       dma_addr_t dma_addr;
-       struct whc_page_list_entry *pl_virt;
-
-       void *bounce_buf;
-       struct scatterlist *bounce_sg;
-       unsigned bounce_offset;
-};
-
-/**
- * struct whc_urb - per URB host controller structure.
- * @urb: the URB this struct is for.
- * @qset: the qset associated to the URB.
- * @dequeue_work: the work to remove the URB when dequeued.
- * @is_async: the URB belongs to async sheduler or not.
- * @status: the status to be returned when calling wusbhc_giveback_urb.
- */
-struct whc_urb {
-       struct urb *urb;
-       struct whc_qset *qset;
-       struct work_struct dequeue_work;
-       bool is_async;
-       int status;
-};
-
-/**
- * whc_std_last - is this sTD the URB's last?
- * @std: the sTD to check.
- */
-static inline bool whc_std_last(struct whc_std *std)
-{
-       return std->ntds_remaining <= 1;
-}
-
-enum whc_update {
-       WHC_UPDATE_ADDED   = 0x01,
-       WHC_UPDATE_REMOVED = 0x02,
-       WHC_UPDATE_UPDATED = 0x04,
-};
-
-/* init.c */
-int whc_init(struct whc *whc);
-void whc_clean_up(struct whc *whc);
-
-/* hw.c */
-void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val);
-int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len);
-void whc_hw_error(struct whc *whc, const char *reason);
-
-/* wusb.c */
-int whc_wusbhc_start(struct wusbhc *wusbhc);
-void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay);
-int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
-                 u8 handle, struct wuie_hdr *wuie);
-int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle);
-int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm);
-int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
-int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots);
-int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
-               const void *ptk, size_t key_size);
-int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
-               const void *gtk, size_t key_size);
-int whc_set_cluster_id(struct whc *whc, u8 bcid);
-
-/* int.c */
-irqreturn_t whc_int_handler(struct usb_hcd *hcd);
-void whc_dn_work(struct work_struct *work);
-
-/* asl.c */
-void asl_start(struct whc *whc);
-void asl_stop(struct whc *whc);
-int  asl_init(struct whc *whc);
-void asl_clean_up(struct whc *whc);
-int  asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
-int  asl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
-void asl_qset_delete(struct whc *whc, struct whc_qset *qset);
-void scan_async_work(struct work_struct *work);
-
-/* pzl.c */
-int  pzl_init(struct whc *whc);
-void pzl_clean_up(struct whc *whc);
-void pzl_start(struct whc *whc);
-void pzl_stop(struct whc *whc);
-int  pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags);
-int  pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status);
-void pzl_qset_delete(struct whc *whc, struct whc_qset *qset);
-void scan_periodic_work(struct work_struct *work);
-
-/* qset.c */
-struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags);
-void qset_free(struct whc *whc, struct whc_qset *qset);
-struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags);
-void qset_delete(struct whc *whc, struct whc_qset *qset);
-void qset_clear(struct whc *whc, struct whc_qset *qset);
-void qset_reset(struct whc *whc, struct whc_qset *qset);
-int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb,
-                gfp_t mem_flags);
-void qset_free_std(struct whc *whc, struct whc_std *std);
-void qset_remove_urb(struct whc *whc, struct whc_qset *qset,
-                           struct urb *urb, int status);
-void process_halted_qtd(struct whc *whc, struct whc_qset *qset,
-                              struct whc_qtd *qtd);
-void process_inactive_qtd(struct whc *whc, struct whc_qset *qset,
-                                struct whc_qtd *qtd);
-enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset);
-void qset_remove_complete(struct whc *whc, struct whc_qset *qset);
-void pzl_update(struct whc *whc, uint32_t wusbcmd);
-void asl_update(struct whc *whc, uint32_t wusbcmd);
-
-/* debug.c */
-void whc_dbg_init(struct whc *whc);
-void whc_dbg_clean_up(struct whc *whc);
-
-#endif /* #ifndef __WHCD_H */
diff --git a/drivers/usb/host/whci/whci-hc.h b/drivers/usb/host/whci/whci-hc.h
deleted file mode 100644 (file)
index 5a86a57..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) data structures.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#ifndef _WHCI_WHCI_HC_H
-#define _WHCI_WHCI_HC_H
-
-#include <linux/list.h>
-
-/**
- * WHCI_PAGE_SIZE - page size use by WHCI
- *
- * WHCI assumes that host system uses pages of 4096 octets.
- */
-#define WHCI_PAGE_SIZE 4096
-
-
-/**
- * QTD_MAX_TXFER_SIZE - max number of bytes to transfer with a single
- * qtd.
- *
- * This is 2^20 - 1.
- */
-#define QTD_MAX_XFER_SIZE 1048575
-
-
-/**
- * struct whc_qtd - Queue Element Transfer Descriptors (qTD)
- *
- * This describes the data for a bulk, control or interrupt transfer.
- *
- * [WHCI] section 3.2.4
- */
-struct whc_qtd {
-       __le32 status; /*< remaining transfer len and transfer status */
-       __le32 options;
-       __le64 page_list_ptr; /*< physical pointer to data buffer page list*/
-       __u8   setup[8];      /*< setup data for control transfers */
-} __attribute__((packed));
-
-#define QTD_STS_ACTIVE     (1 << 31)  /* enable execution of transaction */
-#define QTD_STS_HALTED     (1 << 30)  /* transfer halted */
-#define QTD_STS_DBE        (1 << 29)  /* data buffer error */
-#define QTD_STS_BABBLE     (1 << 28)  /* babble detected */
-#define QTD_STS_RCE        (1 << 27)  /* retry count exceeded */
-#define QTD_STS_LAST_PKT   (1 << 26)  /* set Last Packet Flag in WUSB header */
-#define QTD_STS_INACTIVE   (1 << 25)  /* queue set is marked inactive */
-#define QTD_STS_IALT_VALID (1 << 23)                          /* iAlt field is valid */
-#define QTD_STS_IALT(i)    (QTD_STS_IALT_VALID | ((i) << 20)) /* iAlt field */
-#define QTD_STS_LEN(l)     ((l) << 0) /* transfer length */
-#define QTD_STS_TO_LEN(s)  ((s) & 0x000fffff)
-
-#define QTD_OPT_IOC      (1 << 1) /* page_list_ptr points to buffer directly */
-#define QTD_OPT_SMALL    (1 << 0) /* interrupt on complete */
-
-/**
- * struct whc_itd - Isochronous Queue Element Transfer Descriptors (iTD)
- *
- * This describes the data and other parameters for an isochronous
- * transfer.
- *
- * [WHCI] section 3.2.5
- */
-struct whc_itd {
-       __le16 presentation_time;    /*< presentation time for OUT transfers */
-       __u8   num_segments;         /*< number of data segments in segment list */
-       __u8   status;               /*< command execution status */
-       __le32 options;              /*< misc transfer options */
-       __le64 page_list_ptr;        /*< physical pointer to data buffer page list */
-       __le64 seg_list_ptr;         /*< physical pointer to segment list */
-} __attribute__((packed));
-
-#define ITD_STS_ACTIVE   (1 << 7) /* enable execution of transaction */
-#define ITD_STS_DBE      (1 << 5) /* data buffer error */
-#define ITD_STS_BABBLE   (1 << 4) /* babble detected */
-#define ITD_STS_INACTIVE (1 << 1) /* queue set is marked inactive */
-
-#define ITD_OPT_IOC      (1 << 1) /* interrupt on complete */
-#define ITD_OPT_SMALL    (1 << 0) /* page_list_ptr points to buffer directly */
-
-/**
- * Page list entry.
- *
- * A TD's page list must contain sufficient page list entries for the
- * total data length in the TD.
- *
- * [WHCI] section 3.2.4.3
- */
-struct whc_page_list_entry {
-       __le64 buf_ptr; /*< physical pointer to buffer */
-} __attribute__((packed));
-
-/**
- * struct whc_seg_list_entry - Segment list entry.
- *
- * Describes a portion of the data buffer described in the containing
- * qTD's page list.
- *
- * seg_ptr = qtd->page_list_ptr[qtd->seg_list_ptr[seg].idx].buf_ptr
- *           + qtd->seg_list_ptr[seg].offset;
- *
- * Segments can't cross page boundries.
- *
- * [WHCI] section 3.2.5.5
- */
-struct whc_seg_list_entry {
-       __le16 len;    /*< segment length */
-       __u8   idx;    /*< index into page list */
-       __u8   status; /*< segment status */
-       __le16 offset; /*< 12 bit offset into page */
-} __attribute__((packed));
-
-/**
- * struct whc_qhead - endpoint and status information for a qset.
- *
- * [WHCI] section 3.2.6
- */
-struct whc_qhead {
-       __le64 link; /*< next qset in list */
-       __le32 info1;
-       __le32 info2;
-       __le32 info3;
-       __le16 status;
-       __le16 err_count;  /*< transaction error count */
-       __le32 cur_window;
-       __le32 scratch[3]; /*< h/w scratch area */
-       union {
-               struct whc_qtd qtd;
-               struct whc_itd itd;
-       } overlay;
-} __attribute__((packed));
-
-#define QH_LINK_PTR_MASK (~0x03Full)
-#define QH_LINK_PTR(ptr) ((ptr) & QH_LINK_PTR_MASK)
-#define QH_LINK_IQS      (1 << 4) /* isochronous queue set */
-#define QH_LINK_NTDS(n)  (((n) - 1) << 1) /* number of TDs in queue set */
-#define QH_LINK_T        (1 << 0) /* last queue set in periodic schedule list */
-
-#define QH_INFO1_EP(e)           ((e) << 0)  /* endpoint number */
-#define QH_INFO1_DIR_IN          (1 << 4)    /* IN transfer */
-#define QH_INFO1_DIR_OUT         (0 << 4)    /* OUT transfer */
-#define QH_INFO1_TR_TYPE_CTRL    (0x0 << 5)  /* control transfer */
-#define QH_INFO1_TR_TYPE_ISOC    (0x1 << 5)  /* isochronous transfer */
-#define QH_INFO1_TR_TYPE_BULK    (0x2 << 5)  /* bulk transfer */
-#define QH_INFO1_TR_TYPE_INT     (0x3 << 5)  /* interrupt */
-#define QH_INFO1_TR_TYPE_LP_INT  (0x7 << 5)  /* low power interrupt */
-#define QH_INFO1_DEV_INFO_IDX(i) ((i) << 8)  /* index into device info buffer */
-#define QH_INFO1_SET_INACTIVE    (1 << 15)   /* set inactive after transfer */
-#define QH_INFO1_MAX_PKT_LEN(l)  ((l) << 16) /* maximum packet length */
-
-#define QH_INFO2_BURST(b)        ((b) << 0)  /* maximum burst length */
-#define QH_INFO2_DBP(p)          ((p) << 5)  /* data burst policy (see [WUSB] table 5-7) */
-#define QH_INFO2_MAX_COUNT(c)    ((c) << 8)  /* max isoc/int pkts per zone */
-#define QH_INFO2_RQS             (1 << 15)   /* reactivate queue set */
-#define QH_INFO2_MAX_RETRY(r)    ((r) << 16) /* maximum transaction retries */
-#define QH_INFO2_MAX_SEQ(s)      ((s) << 20) /* maximum sequence number */
-#define QH_INFO3_MAX_DELAY(d)    ((d) << 0)  /* maximum stream delay in 125 us units (isoc only) */
-#define QH_INFO3_INTERVAL(i)     ((i) << 16) /* segment interval in 125 us units (isoc only) */
-
-#define QH_INFO3_TX_RATE(r)      ((r) << 24) /* PHY rate (see [ECMA-368] section 10.3.1.1) */
-#define QH_INFO3_TX_PWR(p)       ((p) << 29) /* transmit power (see [WUSB] section 5.2.1.2) */
-
-#define QH_STATUS_FLOW_CTRL      (1 << 15)
-#define QH_STATUS_ICUR(i)        ((i) << 5)
-#define QH_STATUS_TO_ICUR(s)     (((s) >> 5) & 0x7)
-#define QH_STATUS_SEQ_MASK       0x1f
-
-/**
- * usb_pipe_to_qh_type - USB core pipe type to QH transfer type
- *
- * Returns the QH type field for a USB core pipe type.
- */
-static inline unsigned usb_pipe_to_qh_type(unsigned pipe)
-{
-       static const unsigned type[] = {
-               [PIPE_ISOCHRONOUS] = QH_INFO1_TR_TYPE_ISOC,
-               [PIPE_INTERRUPT]   = QH_INFO1_TR_TYPE_INT,
-               [PIPE_CONTROL]     = QH_INFO1_TR_TYPE_CTRL,
-               [PIPE_BULK]        = QH_INFO1_TR_TYPE_BULK,
-       };
-       return type[usb_pipetype(pipe)];
-}
-
-/**
- * Maxiumum number of TDs in a qset.
- */
-#define WHCI_QSET_TD_MAX 8
-
-/**
- * struct whc_qset - WUSB data transfers to a specific endpoint
- * @qh: the QHead of this qset
- * @qtd: up to 8 qTDs (for qsets for control, bulk and interrupt
- * transfers)
- * @itd: up to 8 iTDs (for qsets for isochronous transfers)
- * @qset_dma: DMA address for this qset
- * @whc: WHCI HC this qset is for
- * @ep: endpoint
- * @stds: list of sTDs queued to this qset
- * @ntds: number of qTDs queued (not necessarily the same as nTDs
- * field in the QH)
- * @td_start: index of the first qTD in the list
- * @td_end: index of next free qTD in the list (provided
- *          ntds < WHCI_QSET_TD_MAX)
- *
- * Queue Sets (qsets) are added to the asynchronous schedule list
- * (ASL) or the periodic zone list (PZL).
- *
- * qsets may contain up to 8 TDs (either qTDs or iTDs as appropriate).
- * Each TD may refer to at most 1 MiB of data. If a single transfer
- * has > 8MiB of data, TDs can be reused as they are completed since
- * the TD list is used as a circular buffer.  Similarly, several
- * (smaller) transfers may be queued in a qset.
- *
- * WHCI controllers may cache portions of the qsets in the ASL and
- * PZL, requiring the WHCD to inform the WHC that the lists have been
- * updated (fields changed or qsets inserted or removed).  For safe
- * insertion and removal of qsets from the lists the schedule must be
- * stopped to avoid races in updating the QH link pointers.
- *
- * Since the HC is free to execute qsets in any order, all transfers
- * to an endpoint should use the same qset to ensure transfers are
- * executed in the order they're submitted.
- *
- * [WHCI] section 3.2.3
- */
-struct whc_qset {
-       struct whc_qhead qh;
-       union {
-               struct whc_qtd qtd[WHCI_QSET_TD_MAX];
-               struct whc_itd itd[WHCI_QSET_TD_MAX];
-       };
-
-       /* private data for WHCD */
-       dma_addr_t qset_dma;
-       struct whc *whc;
-       struct usb_host_endpoint *ep;
-       struct list_head stds;
-       int ntds;
-       int td_start;
-       int td_end;
-       struct list_head list_node;
-       unsigned in_sw_list:1;
-       unsigned in_hw_list:1;
-       unsigned remove:1;
-       unsigned reset:1;
-       struct urb *pause_after_urb;
-       struct completion remove_complete;
-       uint16_t max_packet;
-       uint8_t max_burst;
-       uint8_t max_seq;
-};
-
-static inline void whc_qset_set_link_ptr(u64 *ptr, u64 target)
-{
-       if (target)
-               *ptr = (*ptr & ~(QH_LINK_PTR_MASK | QH_LINK_T)) | QH_LINK_PTR(target);
-       else
-               *ptr = QH_LINK_T;
-}
-
-/**
- * struct di_buf_entry - Device Information (DI) buffer entry.
- *
- * There's one of these per connected device.
- */
-struct di_buf_entry {
-       __le32 availability_info[8]; /*< MAS availability information, one MAS per bit */
-       __le32 addr_sec_info;        /*< addressing and security info */
-       __le32 reserved[7];
-} __attribute__((packed));
-
-#define WHC_DI_SECURE           (1 << 31)
-#define WHC_DI_DISABLE          (1 << 30)
-#define WHC_DI_KEY_IDX(k)       ((k) << 8)
-#define WHC_DI_KEY_IDX_MASK     0x0000ff00
-#define WHC_DI_DEV_ADDR(a)      ((a) << 0)
-#define WHC_DI_DEV_ADDR_MASK    0x000000ff
-
-/**
- * struct dn_buf_entry - Device Notification (DN) buffer entry.
- *
- * [WHCI] section 3.2.8
- */
-struct dn_buf_entry {
-       __u8   msg_size;    /*< number of octets of valid DN data */
-       __u8   reserved1;
-       __u8   src_addr;    /*< source address */
-       __u8   status;      /*< buffer entry status */
-       __le32 tkid;        /*< TKID for source device, valid if secure bit is set */
-       __u8   dn_data[56]; /*< up to 56 octets of DN data */
-} __attribute__((packed));
-
-#define WHC_DN_STATUS_VALID  (1 << 7) /* buffer entry is valid */
-#define WHC_DN_STATUS_SECURE (1 << 6) /* notification received using secure frame */
-
-#define WHC_N_DN_ENTRIES (4096 / sizeof(struct dn_buf_entry))
-
-/* The Add MMC IE WUSB Generic Command may take up to 256 bytes of
-   data. [WHCI] section 2.4.7. */
-#define WHC_GEN_CMD_DATA_LEN 256
-
-/*
- * HC registers.
- *
- * [WHCI] section 2.4
- */
-
-#define WHCIVERSION          0x00
-
-#define WHCSPARAMS           0x04
-#  define WHCSPARAMS_TO_N_MMC_IES(p) (((p) >> 16) & 0xff)
-#  define WHCSPARAMS_TO_N_KEYS(p)    (((p) >> 8) & 0xff)
-#  define WHCSPARAMS_TO_N_DEVICES(p) (((p) >> 0) & 0x7f)
-
-#define WUSBCMD              0x08
-#  define WUSBCMD_BCID(b)            ((b) << 16)
-#  define WUSBCMD_BCID_MASK          (0xff << 16)
-#  define WUSBCMD_ASYNC_QSET_RM      (1 << 12)
-#  define WUSBCMD_PERIODIC_QSET_RM   (1 << 11)
-#  define WUSBCMD_WUSBSI(s)          ((s) << 8)
-#  define WUSBCMD_WUSBSI_MASK        (0x7 << 8)
-#  define WUSBCMD_ASYNC_SYNCED_DB    (1 << 7)
-#  define WUSBCMD_PERIODIC_SYNCED_DB (1 << 6)
-#  define WUSBCMD_ASYNC_UPDATED      (1 << 5)
-#  define WUSBCMD_PERIODIC_UPDATED   (1 << 4)
-#  define WUSBCMD_ASYNC_EN           (1 << 3)
-#  define WUSBCMD_PERIODIC_EN        (1 << 2)
-#  define WUSBCMD_WHCRESET           (1 << 1)
-#  define WUSBCMD_RUN                (1 << 0)
-
-#define WUSBSTS              0x0c
-#  define WUSBSTS_ASYNC_SCHED             (1 << 15)
-#  define WUSBSTS_PERIODIC_SCHED          (1 << 14)
-#  define WUSBSTS_DNTS_SCHED              (1 << 13)
-#  define WUSBSTS_HCHALTED                (1 << 12)
-#  define WUSBSTS_GEN_CMD_DONE            (1 << 9)
-#  define WUSBSTS_CHAN_TIME_ROLLOVER      (1 << 8)
-#  define WUSBSTS_DNTS_OVERFLOW           (1 << 7)
-#  define WUSBSTS_BPST_ADJUSTMENT_CHANGED (1 << 6)
-#  define WUSBSTS_HOST_ERR                (1 << 5)
-#  define WUSBSTS_ASYNC_SCHED_SYNCED      (1 << 4)
-#  define WUSBSTS_PERIODIC_SCHED_SYNCED   (1 << 3)
-#  define WUSBSTS_DNTS_INT                (1 << 2)
-#  define WUSBSTS_ERR_INT                 (1 << 1)
-#  define WUSBSTS_INT                     (1 << 0)
-#  define WUSBSTS_INT_MASK                0x3ff
-
-#define WUSBINTR             0x10
-#  define WUSBINTR_GEN_CMD_DONE             (1 << 9)
-#  define WUSBINTR_CHAN_TIME_ROLLOVER       (1 << 8)
-#  define WUSBINTR_DNTS_OVERFLOW            (1 << 7)
-#  define WUSBINTR_BPST_ADJUSTMENT_CHANGED  (1 << 6)
-#  define WUSBINTR_HOST_ERR                 (1 << 5)
-#  define WUSBINTR_ASYNC_SCHED_SYNCED       (1 << 4)
-#  define WUSBINTR_PERIODIC_SCHED_SYNCED    (1 << 3)
-#  define WUSBINTR_DNTS_INT                 (1 << 2)
-#  define WUSBINTR_ERR_INT                  (1 << 1)
-#  define WUSBINTR_INT                      (1 << 0)
-#  define WUSBINTR_ALL 0x3ff
-
-#define WUSBGENCMDSTS        0x14
-#  define WUSBGENCMDSTS_ACTIVE (1 << 31)
-#  define WUSBGENCMDSTS_ERROR  (1 << 24)
-#  define WUSBGENCMDSTS_IOC    (1 << 23)
-#  define WUSBGENCMDSTS_MMCIE_ADD 0x01
-#  define WUSBGENCMDSTS_MMCIE_RM  0x02
-#  define WUSBGENCMDSTS_SET_MAS   0x03
-#  define WUSBGENCMDSTS_CHAN_STOP 0x04
-#  define WUSBGENCMDSTS_RWP_EN    0x05
-
-#define WUSBGENCMDPARAMS     0x18
-#define WUSBGENADDR          0x20
-#define WUSBASYNCLISTADDR    0x28
-#define WUSBDNTSBUFADDR      0x30
-#define WUSBDEVICEINFOADDR   0x38
-
-#define WUSBSETSECKEYCMD     0x40
-#  define WUSBSETSECKEYCMD_SET    (1 << 31)
-#  define WUSBSETSECKEYCMD_ERASE  (1 << 30)
-#  define WUSBSETSECKEYCMD_GTK    (1 << 8)
-#  define WUSBSETSECKEYCMD_IDX(i) ((i) << 0)
-
-#define WUSBTKID             0x44
-#define WUSBSECKEY           0x48
-#define WUSBPERIODICLISTBASE 0x58
-#define WUSBMASINDEX         0x60
-
-#define WUSBDNTSCTRL         0x64
-#  define WUSBDNTSCTRL_ACTIVE      (1 << 31)
-#  define WUSBDNTSCTRL_INTERVAL(i) ((i) << 8)
-#  define WUSBDNTSCTRL_SLOTS(s)    ((s) << 0)
-
-#define WUSBTIME             0x68
-#  define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff
-
-#define WUSBBPST             0x6c
-#define WUSBDIBUPDATED       0x70
-
-#endif /* #ifndef _WHCI_WHCI_HC_H */
diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c
deleted file mode 100644 (file)
index 8a4d805..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless Host Controller (WHC) WUSB operations.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/uwb/umc.h>
-
-#include "../../wusbcore/wusbhc.h"
-
-#include "whcd.h"
-
-static int whc_update_di(struct whc *whc, int idx)
-{
-       int offset = idx / 32;
-       u32 bit = 1 << (idx % 32);
-
-       le_writel(bit, whc->base + WUSBDIBUPDATED + offset);
-
-       return whci_wait_for(&whc->umc->dev,
-                            whc->base + WUSBDIBUPDATED + offset, bit, 0,
-                            100, "DI update");
-}
-
-/*
- * WHCI starts MMCs based on there being a valid GTK so these need
- * only start/stop the asynchronous and periodic schedules and send a
- * channel stop command.
- */
-
-int whc_wusbhc_start(struct wusbhc *wusbhc)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-
-       asl_start(whc);
-       pzl_start(whc);
-
-       return 0;
-}
-
-void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u32 stop_time, now_time;
-       int ret;
-
-       pzl_stop(whc);
-       asl_stop(whc);
-
-       now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK;
-       stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff;
-       ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0);
-       if (ret == 0)
-               msleep(delay);
-}
-
-int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
-                 u8 handle, struct wuie_hdr *wuie)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u32 params;
-
-       params = (interval << 24)
-               | (repeat_cnt << 16)
-               | (wuie->bLength << 8)
-               | handle;
-
-       return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength);
-}
-
-int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u32 params;
-
-       params = handle;
-
-       return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0);
-}
-
-int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-
-       if (stream_index >= 0)
-               whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index));
-
-       return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm));
-}
-
-int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       int idx = wusb_dev->port_idx;
-       struct di_buf_entry *di = &whc->di_buf[idx];
-       int ret;
-
-       mutex_lock(&whc->mutex);
-
-       uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability);
-       di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK);
-       di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr);
-
-       ret = whc_update_di(whc, idx);
-
-       mutex_unlock(&whc->mutex);
-
-       return ret;
-}
-
-/*
- * Set the number of Device Notification Time Slots (DNTS) and enable
- * device notifications.
- */
-int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       u32 dntsctrl;
-
-       dntsctrl = WUSBDNTSCTRL_ACTIVE
-               | WUSBDNTSCTRL_INTERVAL(interval)
-               | WUSBDNTSCTRL_SLOTS(slots);
-
-       le_writel(dntsctrl, whc->base + WUSBDNTSCTRL);
-
-       return 0;
-}
-
-static int whc_set_key(struct whc *whc, u8 key_index, uint32_t tkid,
-                      const void *key, size_t key_size, bool is_gtk)
-{
-       uint32_t setkeycmd;
-       uint32_t seckey[4];
-       int i;
-       int ret;
-
-       memcpy(seckey, key, key_size);
-       setkeycmd = WUSBSETSECKEYCMD_SET | WUSBSETSECKEYCMD_IDX(key_index);
-       if (is_gtk)
-               setkeycmd |= WUSBSETSECKEYCMD_GTK;
-
-       le_writel(tkid, whc->base + WUSBTKID);
-       for (i = 0; i < 4; i++)
-               le_writel(seckey[i], whc->base + WUSBSECKEY + 4*i);
-       le_writel(setkeycmd, whc->base + WUSBSETSECKEYCMD);
-
-       ret = whci_wait_for(&whc->umc->dev, whc->base + WUSBSETSECKEYCMD,
-                           WUSBSETSECKEYCMD_SET, 0, 100, "set key");
-
-       return ret;
-}
-
-/**
- * whc_set_ptk - set the PTK to use for a device.
- *
- * The index into the key table for this PTK is the same as the
- * device's port index.
- */
-int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
-               const void *ptk, size_t key_size)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       struct di_buf_entry *di = &whc->di_buf[port_idx];
-       int ret;
-
-       mutex_lock(&whc->mutex);
-
-       if (ptk) {
-               ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false);
-               if (ret)
-                       goto out;
-
-               di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK;
-               di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx);
-       } else
-               di->addr_sec_info &= ~WHC_DI_SECURE;
-
-       ret = whc_update_di(whc, port_idx);
-out:
-       mutex_unlock(&whc->mutex);
-       return ret;
-}
-
-/**
- * whc_set_gtk - set the GTK for subsequent broadcast packets
- *
- * The GTK is stored in the last entry in the key table (the previous
- * N_DEVICES entries are for the per-device PTKs).
- */
-int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
-               const void *gtk, size_t key_size)
-{
-       struct whc *whc = wusbhc_to_whc(wusbhc);
-       int ret;
-
-       mutex_lock(&whc->mutex);
-
-       ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true);
-
-       mutex_unlock(&whc->mutex);
-
-       return ret;
-}
-
-int whc_set_cluster_id(struct whc *whc, u8 bcid)
-{
-       whc_write_wusbcmd(whc, WUSBCMD_BCID_MASK, WUSBCMD_BCID(bcid));
-       return 0;
-}
diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig
deleted file mode 100644 (file)
index abc0f36..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Wireless USB Core configuration
-#
-config USB_WUSB
-       tristate "Enable Wireless USB extensions"
-       depends on UWB
-       select CRYPTO
-       select CRYPTO_AES
-       select CRYPTO_CCM
-       help
-         Enable the host-side support for Wireless USB.
-
-          To compile this support select Y (built in). It is safe to
-         select even if you don't have the hardware.
-
-config USB_WUSB_CBAF
-       tristate "Support WUSB Cable Based Association (CBA)"
-       depends on USB
-       help
-         Some WUSB devices support Cable Based Association. It's used to
-         enable the secure communication between the host and the
-         device.
-
-         Enable this option if your WUSB device must to be connected
-         via wired USB before establishing a wireless link.
-
-         It is safe to select even if you don't have a compatible
-         hardware.
-
-config USB_WUSB_CBAF_DEBUG
-       bool "Enable CBA debug messages"
-       depends on USB_WUSB_CBAF
-       help
-         Say Y here if you want the CBA to produce a bunch of debug messages
-         to the system log. Select this if you are having a problem with
-         CBA support and want to see more of what is going on.
-
diff --git a/drivers/usb/wusbcore/Makefile b/drivers/usb/wusbcore/Makefile
deleted file mode 100644 (file)
index d604ccd..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-ccflags-$(CONFIG_USB_WUSB_CBAF_DEBUG) := -DDEBUG
-
-obj-$(CONFIG_USB_WUSB)         += wusbcore.o
-obj-$(CONFIG_USB_HWA_HCD)      += wusb-wa.o
-obj-$(CONFIG_USB_WUSB_CBAF)    += wusb-cbaf.o
-
-
-wusbcore-y :=          \
-       crypto.o        \
-       devconnect.o    \
-       dev-sysfs.o     \
-       mmc.o           \
-       pal.o           \
-       rh.o            \
-       reservation.o   \
-       security.o      \
-       wusbhc.o
-
-wusb-cbaf-y := cbaf.o
-
-wusb-wa-y :=           \
-       wa-hc.o         \
-       wa-nep.o        \
-       wa-rpipe.o      \
-       wa-xfer.o
diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c
deleted file mode 100644 (file)
index af77064..0000000
+++ /dev/null
@@ -1,645 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB - Cable Based Association
- *
- *
- * Copyright (C) 2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * WUSB devices have to be paired (associated in WUSB lingo) so
- * that they can connect to the system.
- *
- * One way of pairing is using CBA-Cable Based Association. First
- * time you plug the device with a cable, association is done between
- * host and device and subsequent times, you can connect wirelessly
- * without having to associate again. That's the idea.
- *
- * This driver does nothing Earth shattering. It just provides an
- * interface to chat with the wire-connected device so we can get a
- * CDID (device ID) that might have been previously associated to a
- * CHID (host ID) and to set up a new <CHID,CDID,CK> triplet
- * (connection context), with the CK being the secret, or connection
- * key. This is the pairing data.
- *
- * When a device with the CBA capability connects, the probe routine
- * just creates a bunch of sysfs files that a user space enumeration
- * manager uses to allow it to connect wirelessly to the system or not.
- *
- * The process goes like this:
- *
- * 1. Device plugs, cbaf is loaded, notifications happen.
- *
- * 2. The connection manager (CM) sees a device with CBAF capability
- *    (the wusb_chid etc. files in /sys/devices/blah/OURDEVICE).
- *
- * 3. The CM writes the host name, supported band groups, and the CHID
- *    (host ID) into the wusb_host_name, wusb_host_band_groups and
- *    wusb_chid files. These get sent to the device and the CDID (if
- *    any) for this host is requested.
- *
- * 4. The CM can verify that the device's supported band groups
- *    (wusb_device_band_groups) are compatible with the host.
- *
- * 5. The CM reads the wusb_cdid file.
- *
- * 6. The CM looks up its database
- *
- * 6.1 If it has a matching CHID,CDID entry, the device has been
- *     authorized before (paired) and nothing further needs to be
- *     done.
- *
- * 6.2 If the CDID is zero (or the CM doesn't find a matching CDID in
- *     its database), the device is assumed to be not known.  The CM
- *     may associate the host with device by: writing a randomly
- *     generated CDID to wusb_cdid and then a random CK to wusb_ck
- *     (this uploads the new CC to the device).
- *
- *     CMD may choose to prompt the user before associating with a new
- *     device.
- *
- * 7. Device is unplugged.
- *
- * When the device tries to connect wirelessly, it will present its
- * CDID to the WUSB host controller.  The CM will query the
- * database. If the CHID/CDID pair found, it will (with a 4-way
- * handshake) challenge the device to demonstrate it has the CK secret
- * key (from our database) without actually exchanging it. Once
- * satisfied, crypto keys are derived from the CK, the device is
- * connected and all communication is encrypted.
- *
- * References:
- *   [WUSB-AM] Association Models Supplement to the Certified Wireless
- *             Universal Serial Bus Specification, version 1.0.
- */
-#include <linux/module.h>
-#include <linux/ctype.h>
-#include <linux/usb.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/uwb.h>
-#include <linux/usb/wusb.h>
-#include <linux/usb/association.h>
-
-#define CBA_NAME_LEN 0x40 /* [WUSB-AM] table 4-7 */
-
-/* An instance of a Cable-Based-Association-Framework device */
-struct cbaf {
-       struct usb_device *usb_dev;
-       struct usb_interface *usb_iface;
-       void *buffer;
-       size_t buffer_size;
-
-       struct wusb_ckhdid chid;
-       char host_name[CBA_NAME_LEN];
-       u16 host_band_groups;
-
-       struct wusb_ckhdid cdid;
-       char device_name[CBA_NAME_LEN];
-       u16 device_band_groups;
-
-       struct wusb_ckhdid ck;
-};
-
-/*
- * Verify that a CBAF USB-interface has what we need
- *
- * According to [WUSB-AM], CBA devices should provide at least two
- * interfaces:
- *  - RETRIEVE_HOST_INFO
- *  - ASSOCIATE
- *
- * If the device doesn't provide these interfaces, we do not know how
- * to deal with it.
- */
-static int cbaf_check(struct cbaf *cbaf)
-{
-       int result;
-       struct device *dev = &cbaf->usb_iface->dev;
-       struct wusb_cbaf_assoc_info *assoc_info;
-       struct wusb_cbaf_assoc_request *assoc_request;
-       size_t assoc_size;
-       void *itr, *top;
-       int ar_rhi = 0, ar_assoc = 0;
-
-       result = usb_control_msg(
-               cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
-               CBAF_REQ_GET_ASSOCIATION_INFORMATION,
-               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-               cbaf->buffer, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Cannot get available association types: %d\n",
-                       result);
-               return result;
-       }
-
-       assoc_info = cbaf->buffer;
-       if (result < sizeof(*assoc_info)) {
-               dev_err(dev, "Not enough data to decode association info "
-                       "header (%zu vs %zu bytes required)\n",
-                       (size_t)result, sizeof(*assoc_info));
-               return result;
-       }
-
-       assoc_size = le16_to_cpu(assoc_info->Length);
-       if (result < assoc_size) {
-               dev_err(dev, "Not enough data to decode association info "
-                       "(%zu vs %zu bytes required)\n",
-                       (size_t)assoc_size, sizeof(*assoc_info));
-               return result;
-       }
-       /*
-        * From now on, we just verify, but won't error out unless we
-        * don't find the AR_TYPE_WUSB_{RETRIEVE_HOST_INFO,ASSOCIATE}
-        * types.
-        */
-       itr = cbaf->buffer + sizeof(*assoc_info);
-       top = cbaf->buffer + assoc_size;
-       dev_dbg(dev, "Found %u association requests (%zu bytes)\n",
-                assoc_info->NumAssociationRequests, assoc_size);
-
-       while (itr < top) {
-               u16 ar_type, ar_subtype;
-               u32 ar_size;
-               const char *ar_name;
-
-               assoc_request = itr;
-
-               if (top - itr < sizeof(*assoc_request)) {
-                       dev_err(dev, "Not enough data to decode association "
-                               "request (%zu vs %zu bytes needed)\n",
-                               top - itr, sizeof(*assoc_request));
-                       break;
-               }
-
-               ar_type = le16_to_cpu(assoc_request->AssociationTypeId);
-               ar_subtype = le16_to_cpu(assoc_request->AssociationSubTypeId);
-               ar_size = le32_to_cpu(assoc_request->AssociationTypeInfoSize);
-               ar_name = "unknown";
-
-               switch (ar_type) {
-               case AR_TYPE_WUSB:
-                       /* Verify we have what is mandated by [WUSB-AM]. */
-                       switch (ar_subtype) {
-                       case AR_TYPE_WUSB_RETRIEVE_HOST_INFO:
-                               ar_name = "RETRIEVE_HOST_INFO";
-                               ar_rhi = 1;
-                               break;
-                       case AR_TYPE_WUSB_ASSOCIATE:
-                               /* send assoc data */
-                               ar_name = "ASSOCIATE";
-                               ar_assoc = 1;
-                               break;
-                       }
-                       break;
-               }
-
-               dev_dbg(dev, "Association request #%02u: 0x%04x/%04x "
-                        "(%zu bytes): %s\n",
-                        assoc_request->AssociationDataIndex, ar_type,
-                        ar_subtype, (size_t)ar_size, ar_name);
-
-               itr += sizeof(*assoc_request);
-       }
-
-       if (!ar_rhi) {
-               dev_err(dev, "Missing RETRIEVE_HOST_INFO association "
-                       "request\n");
-               return -EINVAL;
-       }
-       if (!ar_assoc) {
-               dev_err(dev, "Missing ASSOCIATE association request\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static const struct wusb_cbaf_host_info cbaf_host_info_defaults = {
-       .AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId,
-       .AssociationTypeId        = cpu_to_le16(AR_TYPE_WUSB),
-       .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
-       .AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO),
-       .CHID_hdr                 = WUSB_AR_CHID,
-       .LangID_hdr               = WUSB_AR_LangID,
-       .HostFriendlyName_hdr     = WUSB_AR_HostFriendlyName,
-};
-
-/* Send WUSB host information (CHID and name) to a CBAF device */
-static int cbaf_send_host_info(struct cbaf *cbaf)
-{
-       struct wusb_cbaf_host_info *hi;
-       size_t name_len;
-       size_t hi_size;
-
-       hi = cbaf->buffer;
-       memset(hi, 0, sizeof(*hi));
-       *hi = cbaf_host_info_defaults;
-       hi->CHID = cbaf->chid;
-       hi->LangID = 0; /* FIXME: I guess... */
-       strlcpy(hi->HostFriendlyName, cbaf->host_name, CBA_NAME_LEN);
-       name_len = strlen(cbaf->host_name);
-       hi->HostFriendlyName_hdr.len = cpu_to_le16(name_len);
-       hi_size = sizeof(*hi) + name_len;
-
-       return usb_control_msg(cbaf->usb_dev,
-                       usb_sndctrlpipe(cbaf->usb_dev, 0),
-                       CBAF_REQ_SET_ASSOCIATION_RESPONSE,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       0x0101,
-                       cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       hi, hi_size, USB_CTRL_SET_TIMEOUT);
-}
-
-/*
- * Get device's information (CDID) associated to CHID
- *
- * The device will return it's information (CDID, name, bandgroups)
- * associated to the CHID we have set before, or 0 CDID and default
- * name and bandgroup if no CHID set or unknown.
- */
-static int cbaf_cdid_get(struct cbaf *cbaf)
-{
-       int result;
-       struct device *dev = &cbaf->usb_iface->dev;
-       struct wusb_cbaf_device_info *di;
-       size_t needed;
-
-       di = cbaf->buffer;
-       result = usb_control_msg(
-               cbaf->usb_dev, usb_rcvctrlpipe(cbaf->usb_dev, 0),
-               CBAF_REQ_GET_ASSOCIATION_REQUEST,
-               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-               di, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Cannot request device information: %d\n",
-                       result);
-               return result;
-       }
-
-       needed = result < sizeof(*di) ? sizeof(*di) : le32_to_cpu(di->Length);
-       if (result < needed) {
-               dev_err(dev, "Not enough data in DEVICE_INFO reply (%zu vs "
-                       "%zu bytes needed)\n", (size_t)result, needed);
-               return -ENOENT;
-       }
-
-       strlcpy(cbaf->device_name, di->DeviceFriendlyName, CBA_NAME_LEN);
-       cbaf->cdid = di->CDID;
-       cbaf->device_band_groups = le16_to_cpu(di->BandGroups);
-
-       return 0;
-}
-
-static ssize_t cbaf_wusb_chid_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return sprintf(buf, "%16ph\n", cbaf->chid.data);
-}
-
-static ssize_t cbaf_wusb_chid_store(struct device *dev,
-                                        struct device_attribute *attr,
-                                        const char *buf, size_t size)
-{
-       ssize_t result;
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       result = sscanf(buf,
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx",
-                       &cbaf->chid.data[0] , &cbaf->chid.data[1],
-                       &cbaf->chid.data[2] , &cbaf->chid.data[3],
-                       &cbaf->chid.data[4] , &cbaf->chid.data[5],
-                       &cbaf->chid.data[6] , &cbaf->chid.data[7],
-                       &cbaf->chid.data[8] , &cbaf->chid.data[9],
-                       &cbaf->chid.data[10], &cbaf->chid.data[11],
-                       &cbaf->chid.data[12], &cbaf->chid.data[13],
-                       &cbaf->chid.data[14], &cbaf->chid.data[15]);
-
-       if (result != 16)
-               return -EINVAL;
-
-       result = cbaf_send_host_info(cbaf);
-       if (result < 0)
-               return result;
-       result = cbaf_cdid_get(cbaf);
-       if (result < 0)
-               return result;
-       return size;
-}
-static DEVICE_ATTR(wusb_chid, 0600, cbaf_wusb_chid_show, cbaf_wusb_chid_store);
-
-static ssize_t cbaf_wusb_host_name_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->host_name);
-}
-
-static ssize_t cbaf_wusb_host_name_store(struct device *dev,
-                                        struct device_attribute *attr,
-                                        const char *buf, size_t size)
-{
-       ssize_t result;
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       result = sscanf(buf, "%63s", cbaf->host_name);
-       if (result != 1)
-               return -EINVAL;
-
-       return size;
-}
-static DEVICE_ATTR(wusb_host_name, 0600, cbaf_wusb_host_name_show,
-                                        cbaf_wusb_host_name_store);
-
-static ssize_t cbaf_wusb_host_band_groups_show(struct device *dev,
-                                              struct device_attribute *attr,
-                                              char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->host_band_groups);
-}
-
-static ssize_t cbaf_wusb_host_band_groups_store(struct device *dev,
-                                               struct device_attribute *attr,
-                                               const char *buf, size_t size)
-{
-       ssize_t result;
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-       u16 band_groups = 0;
-
-       result = sscanf(buf, "%04hx", &band_groups);
-       if (result != 1)
-               return -EINVAL;
-
-       cbaf->host_band_groups = band_groups;
-
-       return size;
-}
-
-static DEVICE_ATTR(wusb_host_band_groups, 0600,
-                  cbaf_wusb_host_band_groups_show,
-                  cbaf_wusb_host_band_groups_store);
-
-static const struct wusb_cbaf_device_info cbaf_device_info_defaults = {
-       .Length_hdr               = WUSB_AR_Length,
-       .CDID_hdr                 = WUSB_AR_CDID,
-       .BandGroups_hdr           = WUSB_AR_BandGroups,
-       .LangID_hdr               = WUSB_AR_LangID,
-       .DeviceFriendlyName_hdr   = WUSB_AR_DeviceFriendlyName,
-};
-
-static ssize_t cbaf_wusb_cdid_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return sprintf(buf, "%16ph\n", cbaf->cdid.data);
-}
-
-static ssize_t cbaf_wusb_cdid_store(struct device *dev,
-                               struct device_attribute *attr,
-                               const char *buf, size_t size)
-{
-       ssize_t result;
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-       struct wusb_ckhdid cdid;
-
-       result = sscanf(buf,
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx",
-                       &cdid.data[0] , &cdid.data[1],
-                       &cdid.data[2] , &cdid.data[3],
-                       &cdid.data[4] , &cdid.data[5],
-                       &cdid.data[6] , &cdid.data[7],
-                       &cdid.data[8] , &cdid.data[9],
-                       &cdid.data[10], &cdid.data[11],
-                       &cdid.data[12], &cdid.data[13],
-                       &cdid.data[14], &cdid.data[15]);
-       if (result != 16)
-               return -EINVAL;
-
-       cbaf->cdid = cdid;
-
-       return size;
-}
-static DEVICE_ATTR(wusb_cdid, 0600, cbaf_wusb_cdid_show, cbaf_wusb_cdid_store);
-
-static ssize_t cbaf_wusb_device_band_groups_show(struct device *dev,
-                                                struct device_attribute *attr,
-                                                char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return scnprintf(buf, PAGE_SIZE, "0x%04x\n", cbaf->device_band_groups);
-}
-
-static DEVICE_ATTR(wusb_device_band_groups, 0600,
-                  cbaf_wusb_device_band_groups_show,
-                  NULL);
-
-static ssize_t cbaf_wusb_device_name_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       return scnprintf(buf, PAGE_SIZE, "%s\n", cbaf->device_name);
-}
-static DEVICE_ATTR(wusb_device_name, 0600, cbaf_wusb_device_name_show, NULL);
-
-static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = {
-       .AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId,
-       .AssociationTypeId        = cpu_to_le16(AR_TYPE_WUSB),
-       .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
-       .AssociationSubTypeId     = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE),
-       .Length_hdr               = WUSB_AR_Length,
-       .Length         = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)),
-       .ConnectionContext_hdr    = WUSB_AR_ConnectionContext,
-       .BandGroups_hdr           = WUSB_AR_BandGroups,
-};
-
-static const struct wusb_cbaf_cc_data_fail cbaf_cc_data_fail_defaults = {
-       .AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId,
-       .AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,
-       .Length_hdr               = WUSB_AR_Length,
-       .AssociationStatus_hdr    = WUSB_AR_AssociationStatus,
-};
-
-/*
- * Send a new CC to the device.
- */
-static int cbaf_cc_upload(struct cbaf *cbaf)
-{
-       int result;
-       struct device *dev = &cbaf->usb_iface->dev;
-       struct wusb_cbaf_cc_data *ccd;
-
-       ccd =  cbaf->buffer;
-       *ccd = cbaf_cc_data_defaults;
-       ccd->CHID = cbaf->chid;
-       ccd->CDID = cbaf->cdid;
-       ccd->CK = cbaf->ck;
-       ccd->BandGroups = cpu_to_le16(cbaf->host_band_groups);
-
-       dev_dbg(dev, "Trying to upload CC:\n");
-       dev_dbg(dev, "  CHID       %16ph\n", ccd->CHID.data);
-       dev_dbg(dev, "  CDID       %16ph\n", ccd->CDID.data);
-       dev_dbg(dev, "  Bandgroups 0x%04x\n", cbaf->host_band_groups);
-
-       result = usb_control_msg(
-               cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0),
-               CBAF_REQ_SET_ASSOCIATION_RESPONSE,
-               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-               ccd, sizeof(*ccd), USB_CTRL_SET_TIMEOUT);
-
-       return result;
-}
-
-static ssize_t cbaf_wusb_ck_store(struct device *dev,
-                                 struct device_attribute *attr,
-                                 const char *buf, size_t size)
-{
-       ssize_t result;
-       struct usb_interface *iface = to_usb_interface(dev);
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-
-       result = sscanf(buf,
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx",
-                       &cbaf->ck.data[0] , &cbaf->ck.data[1],
-                       &cbaf->ck.data[2] , &cbaf->ck.data[3],
-                       &cbaf->ck.data[4] , &cbaf->ck.data[5],
-                       &cbaf->ck.data[6] , &cbaf->ck.data[7],
-                       &cbaf->ck.data[8] , &cbaf->ck.data[9],
-                       &cbaf->ck.data[10], &cbaf->ck.data[11],
-                       &cbaf->ck.data[12], &cbaf->ck.data[13],
-                       &cbaf->ck.data[14], &cbaf->ck.data[15]);
-       if (result != 16)
-               return -EINVAL;
-
-       result = cbaf_cc_upload(cbaf);
-       if (result < 0)
-               return result;
-
-       return size;
-}
-static DEVICE_ATTR(wusb_ck, 0600, NULL, cbaf_wusb_ck_store);
-
-static struct attribute *cbaf_dev_attrs[] = {
-       &dev_attr_wusb_host_name.attr,
-       &dev_attr_wusb_host_band_groups.attr,
-       &dev_attr_wusb_chid.attr,
-       &dev_attr_wusb_cdid.attr,
-       &dev_attr_wusb_device_name.attr,
-       &dev_attr_wusb_device_band_groups.attr,
-       &dev_attr_wusb_ck.attr,
-       NULL,
-};
-
-static const struct attribute_group cbaf_dev_attr_group = {
-       .name = NULL,   /* we want them in the same directory */
-       .attrs = cbaf_dev_attrs,
-};
-
-static int cbaf_probe(struct usb_interface *iface,
-                     const struct usb_device_id *id)
-{
-       struct cbaf *cbaf;
-       struct device *dev = &iface->dev;
-       int result = -ENOMEM;
-
-       cbaf = kzalloc(sizeof(*cbaf), GFP_KERNEL);
-       if (cbaf == NULL)
-               goto error_kzalloc;
-       cbaf->buffer = kmalloc(512, GFP_KERNEL);
-       if (cbaf->buffer == NULL)
-               goto error_kmalloc_buffer;
-
-       cbaf->buffer_size = 512;
-       cbaf->usb_dev = usb_get_dev(interface_to_usbdev(iface));
-       cbaf->usb_iface = usb_get_intf(iface);
-       result = cbaf_check(cbaf);
-       if (result < 0) {
-               dev_err(dev, "This device is not WUSB-CBAF compliant and is not supported yet.\n");
-               goto error_check;
-       }
-
-       result = sysfs_create_group(&dev->kobj, &cbaf_dev_attr_group);
-       if (result < 0) {
-               dev_err(dev, "Can't register sysfs attr group: %d\n", result);
-               goto error_create_group;
-       }
-       usb_set_intfdata(iface, cbaf);
-       return 0;
-
-error_create_group:
-error_check:
-       usb_put_intf(iface);
-       usb_put_dev(cbaf->usb_dev);
-       kfree(cbaf->buffer);
-error_kmalloc_buffer:
-       kfree(cbaf);
-error_kzalloc:
-       return result;
-}
-
-static void cbaf_disconnect(struct usb_interface *iface)
-{
-       struct cbaf *cbaf = usb_get_intfdata(iface);
-       struct device *dev = &iface->dev;
-       sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group);
-       usb_set_intfdata(iface, NULL);
-       usb_put_intf(iface);
-       usb_put_dev(cbaf->usb_dev);
-       kfree(cbaf->buffer);
-       /* paranoia: clean up crypto keys */
-       kzfree(cbaf);
-}
-
-static const struct usb_device_id cbaf_id_table[] = {
-       { USB_INTERFACE_INFO(0xef, 0x03, 0x01), },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, cbaf_id_table);
-
-static struct usb_driver cbaf_driver = {
-       .name =         "wusb-cbaf",
-       .id_table =     cbaf_id_table,
-       .probe =        cbaf_probe,
-       .disconnect =   cbaf_disconnect,
-};
-
-module_usb_driver(cbaf_driver);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Wireless USB Cable Based Association");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c
deleted file mode 100644 (file)
index 9ee6648..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Ultra Wide Band
- * AES-128 CCM Encryption
- *
- * Copyright (C) 2007 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * We don't do any encryption here; we use the Linux Kernel's AES-128
- * crypto modules to construct keys and payload blocks in a way
- * defined by WUSB1.0[6]. Check the erratas, as typos are are patched
- * there.
- *
- * Thanks a zillion to John Keys for his help and clarifications over
- * the designed-by-a-committee text.
- *
- * So the idea is that there is this basic Pseudo-Random-Function
- * defined in WUSB1.0[6.5] which is the core of everything. It works
- * by tweaking some blocks, AES crypting them and then xoring
- * something else with them (this seems to be called CBC(AES) -- can
- * you tell I know jack about crypto?). So we just funnel it into the
- * Linux Crypto API.
- *
- * We leave a crypto test module so we can verify that vectors match,
- * every now and then.
- *
- * Block size: 16 bytes -- AES seems to do things in 'block sizes'. I
- *             am learning a lot...
- *
- *             Conveniently, some data structures that need to be
- *             funneled through AES are...16 bytes in size!
- */
-
-#include <crypto/aes.h>
-#include <crypto/algapi.h>
-#include <crypto/hash.h>
-#include <crypto/skcipher.h>
-#include <linux/crypto.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/uwb.h>
-#include <linux/slab.h>
-#include <linux/usb/wusb.h>
-#include <linux/scatterlist.h>
-
-static int debug_crypto_verify;
-
-module_param(debug_crypto_verify, int, 0);
-MODULE_PARM_DESC(debug_crypto_verify, "verify the key generation algorithms");
-
-static void wusb_key_dump(const void *buf, size_t len)
-{
-       print_hex_dump(KERN_ERR, "  ", DUMP_PREFIX_OFFSET, 16, 1,
-                      buf, len, 0);
-}
-
-/*
- * Block of data, as understood by AES-CCM
- *
- * The code assumes this structure is nothing but a 16 byte array
- * (packed in a struct to avoid common mess ups that I usually do with
- * arrays and enforcing type checking).
- */
-struct aes_ccm_block {
-       u8 data[16];
-} __attribute__((packed));
-
-/*
- * Counter-mode Blocks (WUSB1.0[6.4])
- *
- * According to CCM (or so it seems), for the purpose of calculating
- * the MIC, the message is broken in N counter-mode blocks, B0, B1,
- * ... BN.
- *
- * B0 contains flags, the CCM nonce and l(m).
- *
- * B1 contains l(a), the MAC header, the encryption offset and padding.
- *
- * If EO is nonzero, additional blocks are built from payload bytes
- * until EO is exhausted (FIXME: padding to 16 bytes, I guess). The
- * padding is not xmitted.
- */
-
-/* WUSB1.0[T6.4] */
-struct aes_ccm_b0 {
-       u8 flags;       /* 0x59, per CCM spec */
-       struct aes_ccm_nonce ccm_nonce;
-       __be16 lm;
-} __attribute__((packed));
-
-/* WUSB1.0[T6.5] */
-struct aes_ccm_b1 {
-       __be16 la;
-       u8 mac_header[10];
-       __le16 eo;
-       u8 security_reserved;   /* This is always zero */
-       u8 padding;             /* 0 */
-} __attribute__((packed));
-
-/*
- * Encryption Blocks (WUSB1.0[6.4.4])
- *
- * CCM uses Ax blocks to generate a keystream with which the MIC and
- * the message's payload are encoded. A0 always encrypts/decrypts the
- * MIC. Ax (x>0) are used for the successive payload blocks.
- *
- * The x is the counter, and is increased for each block.
- */
-struct aes_ccm_a {
-       u8 flags;       /* 0x01, per CCM spec */
-       struct aes_ccm_nonce ccm_nonce;
-       __be16 counter; /* Value of x */
-} __attribute__((packed));
-
-/* Scratch space for MAC calculations. */
-struct wusb_mac_scratch {
-       struct aes_ccm_b0 b0;
-       struct aes_ccm_b1 b1;
-       struct aes_ccm_a ax;
-};
-
-/*
- * CC-MAC function WUSB1.0[6.5]
- *
- * Take a data string and produce the encrypted CBC Counter-mode MIC
- *
- * Note the names for most function arguments are made to (more or
- * less) match those used in the pseudo-function definition given in
- * WUSB1.0[6.5].
- *
- * @tfm_cbc: CBC(AES) blkcipher handle (initialized)
- *
- * @tfm_aes: AES cipher handle (initialized)
- *
- * @mic: buffer for placing the computed MIC (Message Integrity
- *       Code). This is exactly 8 bytes, and we expect the buffer to
- *       be at least eight bytes in length.
- *
- * @key: 128 bit symmetric key
- *
- * @n: CCM nonce
- *
- * @a: ASCII string, 14 bytes long (I guess zero padded if needed;
- *     we use exactly 14 bytes).
- *
- * @b: data stream to be processed
- *
- * @blen: size of b...
- *
- * Still not very clear how this is done, but looks like this: we
- * create block B0 (as WUSB1.0[6.5] says), then we AES-crypt it with
- * @key. We bytewise xor B0 with B1 (1) and AES-crypt that. Then we
- * take the payload and divide it in blocks (16 bytes), xor them with
- * the previous crypto result (16 bytes) and crypt it, repeat the next
- * block with the output of the previous one, rinse wash. So we use
- * the CBC-MAC(AES) shash, that does precisely that. The IV (Initial
- * Vector) is 16 bytes and is set to zero, so
- *
- * (1) Created as 6.5 says, again, using as l(a) 'Blen + 14', and
- *     using the 14 bytes of @a to fill up
- *     b1.{mac_header,e0,security_reserved,padding}.
- *
- * NOTE: The definition of l(a) in WUSB1.0[6.5] vs the definition of
- *       l(m) is orthogonal, they bear no relationship, so it is not
- *       in conflict with the parameter's relation that
- *       WUSB1.0[6.4.2]) defines.
- *
- * NOTE: WUSB1.0[A.1]: Host Nonce is missing a nibble? (1e); fixed in
- *       first errata released on 2005/07.
- *
- * NOTE: we need to clean IV to zero at each invocation to make sure
- *       we start with a fresh empty Initial Vector, so that the CBC
- *       works ok.
- *
- * NOTE: blen is not aligned to a block size, we'll pad zeros, that's
- *       what sg[4] is for. Maybe there is a smarter way to do this.
- */
-static int wusb_ccm_mac(struct crypto_shash *tfm_cbcmac,
-                       struct wusb_mac_scratch *scratch,
-                       void *mic,
-                       const struct aes_ccm_nonce *n,
-                       const struct aes_ccm_label *a, const void *b,
-                       size_t blen)
-{
-       SHASH_DESC_ON_STACK(desc, tfm_cbcmac);
-       u8 iv[AES_BLOCK_SIZE];
-
-       /*
-        * These checks should be compile time optimized out
-        * ensure @a fills b1's mac_header and following fields
-        */
-       BUILD_BUG_ON(sizeof(*a) != sizeof(scratch->b1) - sizeof(scratch->b1.la));
-       BUILD_BUG_ON(sizeof(scratch->b0) != sizeof(struct aes_ccm_block));
-       BUILD_BUG_ON(sizeof(scratch->b1) != sizeof(struct aes_ccm_block));
-       BUILD_BUG_ON(sizeof(scratch->ax) != sizeof(struct aes_ccm_block));
-
-       /* Setup B0 */
-       scratch->b0.flags = 0x59;       /* Format B0 */
-       scratch->b0.ccm_nonce = *n;
-       scratch->b0.lm = cpu_to_be16(0);        /* WUSB1.0[6.5] sez l(m) is 0 */
-
-       /* Setup B1
-        *
-        * The WUSB spec is anything but clear! WUSB1.0[6.5]
-        * says that to initialize B1 from A with 'l(a) = blen +
-        * 14'--after clarification, it means to use A's contents
-        * for MAC Header, EO, sec reserved and padding.
-        */
-       scratch->b1.la = cpu_to_be16(blen + 14);
-       memcpy(&scratch->b1.mac_header, a, sizeof(*a));
-
-       desc->tfm = tfm_cbcmac;
-       crypto_shash_init(desc);
-       crypto_shash_update(desc, (u8 *)&scratch->b0, sizeof(scratch->b0) +
-                                                     sizeof(scratch->b1));
-       crypto_shash_finup(desc, b, blen, iv);
-
-       /* Now we crypt the MIC Tag (*iv) with Ax -- values per WUSB1.0[6.5]
-        * The procedure is to AES crypt the A0 block and XOR the MIC
-        * Tag against it; we only do the first 8 bytes and place it
-        * directly in the destination buffer.
-        */
-       scratch->ax.flags = 0x01;               /* as per WUSB 1.0 spec */
-       scratch->ax.ccm_nonce = *n;
-       scratch->ax.counter = 0;
-
-       /* reuse the CBC-MAC transform to perform the single block encryption */
-       crypto_shash_digest(desc, (u8 *)&scratch->ax, sizeof(scratch->ax),
-                           (u8 *)&scratch->ax);
-
-       crypto_xor_cpy(mic, (u8 *)&scratch->ax, iv, 8);
-
-       return 8;
-}
-
-/*
- * WUSB Pseudo Random Function (WUSB1.0[6.5])
- *
- * @b: buffer to the source data; cannot be a global or const local
- *     (will confuse the scatterlists)
- */
-ssize_t wusb_prf(void *out, size_t out_size,
-                const u8 key[16], const struct aes_ccm_nonce *_n,
-                const struct aes_ccm_label *a,
-                const void *b, size_t blen, size_t len)
-{
-       ssize_t result, bytes = 0, bitr;
-       struct aes_ccm_nonce n = *_n;
-       struct crypto_shash *tfm_cbcmac;
-       struct wusb_mac_scratch scratch;
-       u64 sfn = 0;
-       __le64 sfn_le;
-
-       tfm_cbcmac = crypto_alloc_shash("cbcmac(aes)", 0, 0);
-       if (IS_ERR(tfm_cbcmac)) {
-               result = PTR_ERR(tfm_cbcmac);
-               printk(KERN_ERR "E: can't load CBCMAC-AES: %d\n", (int)result);
-               goto error_alloc_cbcmac;
-       }
-
-       result = crypto_shash_setkey(tfm_cbcmac, key, AES_BLOCK_SIZE);
-       if (result < 0) {
-               printk(KERN_ERR "E: can't set CBCMAC-AES key: %d\n", (int)result);
-               goto error_setkey_cbcmac;
-       }
-
-       for (bitr = 0; bitr < (len + 63) / 64; bitr++) {
-               sfn_le = cpu_to_le64(sfn++);
-               memcpy(&n.sfn, &sfn_le, sizeof(n.sfn)); /* n.sfn++... */
-               result = wusb_ccm_mac(tfm_cbcmac, &scratch, out + bytes,
-                                     &n, a, b, blen);
-               if (result < 0)
-                       goto error_ccm_mac;
-               bytes += result;
-       }
-       result = bytes;
-
-error_ccm_mac:
-error_setkey_cbcmac:
-       crypto_free_shash(tfm_cbcmac);
-error_alloc_cbcmac:
-       return result;
-}
-
-/* WUSB1.0[A.2] test vectors */
-static const u8 stv_hsmic_key[16] = {
-       0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d,
-       0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f
-};
-
-static const struct aes_ccm_nonce stv_hsmic_n = {
-       .sfn = { 0 },
-       .tkid = { 0x76, 0x98, 0x01,  },
-       .dest_addr = { .data = { 0xbe, 0x00 } },
-               .src_addr = { .data = { 0x76, 0x98 } },
-};
-
-/*
- * Out-of-band MIC Generation verification code
- *
- */
-static int wusb_oob_mic_verify(void)
-{
-       int result;
-       u8 mic[8];
-       /* WUSB1.0[A.2] test vectors */
-       static const struct usb_handshake stv_hsmic_hs = {
-               .bMessageNumber = 2,
-               .bStatus        = 00,
-               .tTKID          = { 0x76, 0x98, 0x01 },
-               .bReserved      = 00,
-               .CDID           = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
-                                   0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
-                                   0x3c, 0x3d, 0x3e, 0x3f },
-               .nonce          = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
-                                   0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
-                                   0x2c, 0x2d, 0x2e, 0x2f },
-               .MIC            = { 0x75, 0x6a, 0x97, 0x51, 0x0c, 0x8c,
-                                   0x14, 0x7b },
-       };
-       size_t hs_size;
-
-       result = wusb_oob_mic(mic, stv_hsmic_key, &stv_hsmic_n, &stv_hsmic_hs);
-       if (result < 0)
-               printk(KERN_ERR "E: WUSB OOB MIC test: failed: %d\n", result);
-       else if (memcmp(stv_hsmic_hs.MIC, mic, sizeof(mic))) {
-               printk(KERN_ERR "E: OOB MIC test: "
-                      "mismatch between MIC result and WUSB1.0[A2]\n");
-               hs_size = sizeof(stv_hsmic_hs) - sizeof(stv_hsmic_hs.MIC);
-               printk(KERN_ERR "E: Handshake2 in: (%zu bytes)\n", hs_size);
-               wusb_key_dump(&stv_hsmic_hs, hs_size);
-               printk(KERN_ERR "E: CCM Nonce in: (%zu bytes)\n",
-                      sizeof(stv_hsmic_n));
-               wusb_key_dump(&stv_hsmic_n, sizeof(stv_hsmic_n));
-               printk(KERN_ERR "E: MIC out:\n");
-               wusb_key_dump(mic, sizeof(mic));
-               printk(KERN_ERR "E: MIC out (from WUSB1.0[A.2]):\n");
-               wusb_key_dump(stv_hsmic_hs.MIC, sizeof(stv_hsmic_hs.MIC));
-               result = -EINVAL;
-       } else
-               result = 0;
-       return result;
-}
-
-/*
- * Test vectors for Key derivation
- *
- * These come from WUSB1.0[6.5.1], the vectors in WUSB1.0[A.1]
- * (errata corrected in 2005/07).
- */
-static const u8 stv_key_a1[16] __attribute__ ((__aligned__(4))) = {
-       0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87,
-       0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f
-};
-
-static const struct aes_ccm_nonce stv_keydvt_n_a1 = {
-       .sfn = { 0 },
-       .tkid = { 0x76, 0x98, 0x01,  },
-       .dest_addr = { .data = { 0xbe, 0x00 } },
-       .src_addr = { .data = { 0x76, 0x98 } },
-};
-
-static const struct wusb_keydvt_out stv_keydvt_out_a1 = {
-       .kck = {
-               0x4b, 0x79, 0xa3, 0xcf, 0xe5, 0x53, 0x23, 0x9d,
-               0xd7, 0xc1, 0x6d, 0x1c, 0x2d, 0xab, 0x6d, 0x3f
-       },
-       .ptk = {
-               0xc8, 0x70, 0x62, 0x82, 0xb6, 0x7c, 0xe9, 0x06,
-               0x7b, 0xc5, 0x25, 0x69, 0xf2, 0x36, 0x61, 0x2d
-       }
-};
-
-/*
- * Performa a test to make sure we match the vectors defined in
- * WUSB1.0[A.1](Errata2006/12)
- */
-static int wusb_key_derive_verify(void)
-{
-       int result = 0;
-       struct wusb_keydvt_out keydvt_out;
-       /* These come from WUSB1.0[A.1] + 2006/12 errata */
-       static const struct wusb_keydvt_in stv_keydvt_in_a1 = {
-               .hnonce = {
-                       0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-                       0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
-               },
-               .dnonce = {
-                       0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
-                       0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f
-               }
-       };
-
-       result = wusb_key_derive(&keydvt_out, stv_key_a1, &stv_keydvt_n_a1,
-                                &stv_keydvt_in_a1);
-       if (result < 0)
-               printk(KERN_ERR "E: WUSB key derivation test: "
-                      "derivation failed: %d\n", result);
-       if (memcmp(&stv_keydvt_out_a1, &keydvt_out, sizeof(keydvt_out))) {
-               printk(KERN_ERR "E: WUSB key derivation test: "
-                      "mismatch between key derivation result "
-                      "and WUSB1.0[A1] Errata 2006/12\n");
-               printk(KERN_ERR "E: keydvt in: key\n");
-               wusb_key_dump(stv_key_a1, sizeof(stv_key_a1));
-               printk(KERN_ERR "E: keydvt in: nonce\n");
-               wusb_key_dump(&stv_keydvt_n_a1, sizeof(stv_keydvt_n_a1));
-               printk(KERN_ERR "E: keydvt in: hnonce & dnonce\n");
-               wusb_key_dump(&stv_keydvt_in_a1, sizeof(stv_keydvt_in_a1));
-               printk(KERN_ERR "E: keydvt out: KCK\n");
-               wusb_key_dump(&keydvt_out.kck, sizeof(keydvt_out.kck));
-               printk(KERN_ERR "E: keydvt out: PTK\n");
-               wusb_key_dump(&keydvt_out.ptk, sizeof(keydvt_out.ptk));
-               result = -EINVAL;
-       } else
-               result = 0;
-       return result;
-}
-
-/*
- * Initialize crypto system
- *
- * FIXME: we do nothing now, other than verifying. Later on we'll
- * cache the encryption stuff, so that's why we have a separate init.
- */
-int wusb_crypto_init(void)
-{
-       int result;
-
-       if (debug_crypto_verify) {
-               result = wusb_key_derive_verify();
-               if (result < 0)
-                       return result;
-               return wusb_oob_mic_verify();
-       }
-       return 0;
-}
-
-void wusb_crypto_exit(void)
-{
-       /* FIXME: free cached crypto transforms */
-}
diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c
deleted file mode 100644 (file)
index 67b0a4c..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB devices
- * sysfs bindings
- *
- * Copyright (C) 2007 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Get them out of the way...
- */
-
-#include <linux/jiffies.h>
-#include <linux/ctype.h>
-#include <linux/workqueue.h>
-#include "wusbhc.h"
-
-static ssize_t wusb_disconnect_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t size)
-{
-       struct usb_device *usb_dev;
-       struct wusbhc *wusbhc;
-       unsigned command;
-       u8 port_idx;
-
-       if (sscanf(buf, "%u", &command) != 1)
-               return -EINVAL;
-       if (command == 0)
-               return size;
-       usb_dev = to_usb_device(dev);
-       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
-       if (wusbhc == NULL)
-               return -ENODEV;
-
-       mutex_lock(&wusbhc->mutex);
-       port_idx = wusb_port_no_to_idx(usb_dev->portnum);
-       __wusbhc_dev_disable(wusbhc, port_idx);
-       mutex_unlock(&wusbhc->mutex);
-       wusbhc_put(wusbhc);
-       return size;
-}
-static DEVICE_ATTR_WO(wusb_disconnect);
-
-static ssize_t wusb_cdid_show(struct device *dev,
-                             struct device_attribute *attr, char *buf)
-{
-       ssize_t result;
-       struct wusb_dev *wusb_dev;
-
-       wusb_dev = wusb_dev_get_by_usb_dev(to_usb_device(dev));
-       if (wusb_dev == NULL)
-               return -ENODEV;
-       result = sprintf(buf, "%16ph\n", wusb_dev->cdid.data);
-       wusb_dev_put(wusb_dev);
-       return result;
-}
-static DEVICE_ATTR_RO(wusb_cdid);
-
-static ssize_t wusb_ck_store(struct device *dev,
-                            struct device_attribute *attr,
-                            const char *buf, size_t size)
-{
-       int result;
-       struct usb_device *usb_dev;
-       struct wusbhc *wusbhc;
-       struct wusb_ckhdid ck;
-
-       result = sscanf(buf,
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx\n",
-                       &ck.data[0] , &ck.data[1],
-                       &ck.data[2] , &ck.data[3],
-                       &ck.data[4] , &ck.data[5],
-                       &ck.data[6] , &ck.data[7],
-                       &ck.data[8] , &ck.data[9],
-                       &ck.data[10], &ck.data[11],
-                       &ck.data[12], &ck.data[13],
-                       &ck.data[14], &ck.data[15]);
-       if (result != 16)
-               return -EINVAL;
-
-       usb_dev = to_usb_device(dev);
-       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
-       if (wusbhc == NULL)
-               return -ENODEV;
-       result = wusb_dev_4way_handshake(wusbhc, usb_dev->wusb_dev, &ck);
-       memzero_explicit(&ck, sizeof(ck));
-       wusbhc_put(wusbhc);
-       return result < 0 ? result : size;
-}
-static DEVICE_ATTR_WO(wusb_ck);
-
-static struct attribute *wusb_dev_attrs[] = {
-               &dev_attr_wusb_disconnect.attr,
-               &dev_attr_wusb_cdid.attr,
-               &dev_attr_wusb_ck.attr,
-               NULL,
-};
-
-static const struct attribute_group wusb_dev_attr_group = {
-       .name = NULL,   /* we want them in the same directory */
-       .attrs = wusb_dev_attrs,
-};
-
-int wusb_dev_sysfs_add(struct wusbhc *wusbhc, struct usb_device *usb_dev,
-                      struct wusb_dev *wusb_dev)
-{
-       int result = sysfs_create_group(&usb_dev->dev.kobj,
-                                       &wusb_dev_attr_group);
-       struct device *dev = &usb_dev->dev;
-       if (result < 0)
-               dev_err(dev, "Cannot register WUSB-dev attributes: %d\n",
-                       result);
-       return result;
-}
-
-void wusb_dev_sysfs_rm(struct wusb_dev *wusb_dev)
-{
-       struct usb_device *usb_dev = wusb_dev->usb_dev;
-       if (usb_dev)
-               sysfs_remove_group(&usb_dev->dev.kobj, &wusb_dev_attr_group);
-}
diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c
deleted file mode 100644 (file)
index 1170f8b..0000000
+++ /dev/null
@@ -1,1085 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
- * Device Connect handling
- *
- * Copyright (C) 2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- * FIXME: this file needs to be broken up, it's grown too big
- *
- *
- * WUSB1.0[7.1, 7.5.1, ]
- *
- * WUSB device connection is kind of messy. Some background:
- *
- *     When a device wants to connect it scans the UWB radio channels
- *     looking for a WUSB Channel; a WUSB channel is defined by MMCs
- *     (Micro Managed Commands or something like that) [see
- *     Design-overview for more on this] .
- *
- * So, device scans the radio, finds MMCs and thus a host and checks
- * when the next DNTS is. It sends a Device Notification Connect
- * (DN_Connect); the host picks it up (through nep.c and notif.c, ends
- * up in wusb_devconnect_ack(), which creates a wusb_dev structure in
- * wusbhc->port[port_number].wusb_dev), assigns an unauth address
- * to the device (this means from 0x80 to 0xfe) and sends, in the MMC
- * a Connect Ack Information Element (ConnAck IE).
- *
- * So now the device now has a WUSB address. From now on, we use
- * that to talk to it in the RPipes.
- *
- * ASSUMPTIONS:
- *
- *  - We use the the as device address the port number where it is
- *    connected (port 0 doesn't exist). For unauth, it is 128 + that.
- *
- * ROADMAP:
- *
- *   This file contains the logic for doing that--entry points:
- *
- *   wusb_devconnect_ack()      Ack a device until _acked() called.
- *                              Called by notif.c:wusb_handle_dn_connect()
- *                              when a DN_Connect is received.
- *
- *     wusb_devconnect_acked()  Ack done, release resources.
- *
- *   wusb_handle_dn_alive()     Called by notif.c:wusb_handle_dn()
- *                              for processing a DN_Alive pong from a device.
- *
- *   wusb_handle_dn_disconnect()Called by notif.c:wusb_handle_dn() to
- *                              process a disconnect request from a
- *                              device.
- *
- *   __wusb_dev_disable()       Called by rh.c:wusbhc_rh_clear_port_feat() when
- *                              disabling a port.
- *
- *   wusb_devconnect_create()   Called when creating the host by
- *                              lc.c:wusbhc_create().
- *
- *   wusb_devconnect_destroy()  Cleanup called removing the host. Called
- *                              by lc.c:wusbhc_destroy().
- *
- *   Each Wireless USB host maintains a list of DN_Connect requests
- *   (actually we maintain a list of pending Connect Acks, the
- *   wusbhc->ca_list).
- *
- * LIFE CYCLE OF port->wusb_dev
- *
- *   Before the @wusbhc structure put()s the reference it owns for
- *   port->wusb_dev [and clean the wusb_dev pointer], it needs to
- *   lock @wusbhc->mutex.
- */
-
-#include <linux/jiffies.h>
-#include <linux/ctype.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/export.h>
-#include "wusbhc.h"
-
-static void wusbhc_devconnect_acked_work(struct work_struct *work);
-
-static void wusb_dev_free(struct wusb_dev *wusb_dev)
-{
-       kfree(wusb_dev);
-}
-
-static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)
-{
-       struct wusb_dev *wusb_dev;
-
-       wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL);
-       if (wusb_dev == NULL)
-               goto err;
-
-       wusb_dev->wusbhc = wusbhc;
-
-       INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work);
-
-       return wusb_dev;
-err:
-       wusb_dev_free(wusb_dev);
-       return NULL;
-}
-
-
-/*
- * Using the Connect-Ack list, fill out the @wusbhc Connect-Ack WUSB IE
- * properly so that it can be added to the MMC.
- *
- * We just get the @wusbhc->ca_list and fill out the first four ones or
- * less (per-spec WUSB1.0[7.5, before T7-38). If the ConnectAck WUSB
- * IE is not allocated, we alloc it.
- *
- * @wusbhc->mutex must be taken
- */
-static void wusbhc_fill_cack_ie(struct wusbhc *wusbhc)
-{
-       unsigned cnt;
-       struct wusb_dev *dev_itr;
-       struct wuie_connect_ack *cack_ie;
-
-       cack_ie = &wusbhc->cack_ie;
-       cnt = 0;
-       list_for_each_entry(dev_itr, &wusbhc->cack_list, cack_node) {
-               cack_ie->blk[cnt].CDID = dev_itr->cdid;
-               cack_ie->blk[cnt].bDeviceAddress = dev_itr->addr;
-               if (++cnt >= WUIE_ELT_MAX)
-                       break;
-       }
-       cack_ie->hdr.bLength = sizeof(cack_ie->hdr)
-               + cnt * sizeof(cack_ie->blk[0]);
-}
-
-/*
- * Register a new device that wants to connect
- *
- * A new device wants to connect, so we add it to the Connect-Ack
- * list. We give it an address in the unauthorized range (bit 8 set);
- * user space will have to drive authorization further on.
- *
- * @dev_addr: address to use for the device (which is also the port
- *            number).
- *
- * @wusbhc->mutex must be taken
- */
-static struct wusb_dev *wusbhc_cack_add(struct wusbhc *wusbhc,
-                                       struct wusb_dn_connect *dnc,
-                                       const char *pr_cdid, u8 port_idx)
-{
-       struct device *dev = wusbhc->dev;
-       struct wusb_dev *wusb_dev;
-       int new_connection = wusb_dn_connect_new_connection(dnc);
-       u8 dev_addr;
-       int result;
-
-       /* Is it registered already? */
-       list_for_each_entry(wusb_dev, &wusbhc->cack_list, cack_node)
-               if (!memcmp(&wusb_dev->cdid, &dnc->CDID,
-                           sizeof(wusb_dev->cdid)))
-                       return wusb_dev;
-       /* We don't have it, create an entry, register it */
-       wusb_dev = wusb_dev_alloc(wusbhc);
-       if (wusb_dev == NULL)
-               return NULL;
-       wusb_dev_init(wusb_dev);
-       wusb_dev->cdid = dnc->CDID;
-       wusb_dev->port_idx = port_idx;
-
-       /*
-        * Devices are always available within the cluster reservation
-        * and since the hardware will take the intersection of the
-        * per-device availability and the cluster reservation, the
-        * per-device availability can simply be set to always
-        * available.
-        */
-       bitmap_fill(wusb_dev->availability.bm, UWB_NUM_MAS);
-
-       /* FIXME: handle reconnects instead of assuming connects are
-          always new. */
-       if (1 && new_connection == 0)
-               new_connection = 1;
-       if (new_connection) {
-               dev_addr = (port_idx + 2) | WUSB_DEV_ADDR_UNAUTH;
-
-               dev_info(dev, "Connecting new WUSB device to address %u, "
-                       "port %u\n", dev_addr, port_idx);
-
-               result = wusb_set_dev_addr(wusbhc, wusb_dev, dev_addr);
-               if (result < 0)
-                       return NULL;
-       }
-       wusb_dev->entry_ts = jiffies;
-       list_add_tail(&wusb_dev->cack_node, &wusbhc->cack_list);
-       wusbhc->cack_count++;
-       wusbhc_fill_cack_ie(wusbhc);
-
-       return wusb_dev;
-}
-
-/*
- * Remove a Connect-Ack context entry from the HCs view
- *
- * @wusbhc->mutex must be taken
- */
-static void wusbhc_cack_rm(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       list_del_init(&wusb_dev->cack_node);
-       wusbhc->cack_count--;
-       wusbhc_fill_cack_ie(wusbhc);
-}
-
-/*
- * @wusbhc->mutex must be taken */
-static
-void wusbhc_devconnect_acked(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       wusbhc_cack_rm(wusbhc, wusb_dev);
-       if (wusbhc->cack_count)
-               wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr);
-       else
-               wusbhc_mmcie_rm(wusbhc, &wusbhc->cack_ie.hdr);
-}
-
-static void wusbhc_devconnect_acked_work(struct work_struct *work)
-{
-       struct wusb_dev *wusb_dev = container_of(work, struct wusb_dev,
-                                                devconnect_acked_work);
-       struct wusbhc *wusbhc = wusb_dev->wusbhc;
-
-       mutex_lock(&wusbhc->mutex);
-       wusbhc_devconnect_acked(wusbhc, wusb_dev);
-       mutex_unlock(&wusbhc->mutex);
-
-       wusb_dev_put(wusb_dev);
-}
-
-/*
- * Ack a device for connection
- *
- * FIXME: docs
- *
- * @pr_cdid:   Printable CDID...hex Use @dnc->cdid for the real deal.
- *
- * So we get the connect ack IE (may have been allocated already),
- * find an empty connect block, an empty virtual port, create an
- * address with it (see below), make it an unauth addr [bit 7 set] and
- * set the MMC.
- *
- * Addresses: because WUSB hosts have no downstream hubs, we can do a
- *            1:1 mapping between 'port number' and device
- *            address. This simplifies many things, as during this
- *            initial connect phase the USB stack has no knowledge of
- *            the device and hasn't assigned an address yet--we know
- *            USB's choose_address() will use the same heuristics we
- *            use here, so we can assume which address will be assigned.
- *
- *            USB stack always assigns address 1 to the root hub, so
- *            to the port number we add 2 (thus virtual port #0 is
- *            addr #2).
- *
- * @wusbhc shall be referenced
- */
-static
-void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc,
-                          const char *pr_cdid)
-{
-       int result;
-       struct device *dev = wusbhc->dev;
-       struct wusb_dev *wusb_dev;
-       struct wusb_port *port;
-       unsigned idx;
-
-       mutex_lock(&wusbhc->mutex);
-
-       /* Check we are not handling it already */
-       for (idx = 0; idx < wusbhc->ports_max; idx++) {
-               port = wusb_port_by_idx(wusbhc, idx);
-               if (port->wusb_dev
-                   && memcmp(&dnc->CDID, &port->wusb_dev->cdid, sizeof(dnc->CDID)) == 0)
-                       goto error_unlock;
-       }
-       /* Look up those fake ports we have for a free one */
-       for (idx = 0; idx < wusbhc->ports_max; idx++) {
-               port = wusb_port_by_idx(wusbhc, idx);
-               if ((port->status & USB_PORT_STAT_POWER)
-                   && !(port->status & USB_PORT_STAT_CONNECTION))
-                       break;
-       }
-       if (idx >= wusbhc->ports_max) {
-               dev_err(dev, "Host controller can't connect more devices "
-                       "(%u already connected); device %s rejected\n",
-                       wusbhc->ports_max, pr_cdid);
-               /* NOTE: we could send a WUIE_Disconnect here, but we haven't
-                *       event acked, so the device will eventually timeout the
-                *       connection, right? */
-               goto error_unlock;
-       }
-
-       /* Make sure we are using no crypto on that "virtual port" */
-       wusbhc->set_ptk(wusbhc, idx, 0, NULL, 0);
-
-       /* Grab a filled in Connect-Ack context, fill out the
-        * Connect-Ack Wireless USB IE, set the MMC */
-       wusb_dev = wusbhc_cack_add(wusbhc, dnc, pr_cdid, idx);
-       if (wusb_dev == NULL)
-               goto error_unlock;
-       result = wusbhc_mmcie_set(wusbhc, 0, 0, &wusbhc->cack_ie.hdr);
-       if (result < 0)
-               goto error_unlock;
-       /* Give the device at least 2ms (WUSB1.0[7.5.1p3]), let's do
-        * three for a good measure */
-       msleep(3);
-       port->wusb_dev = wusb_dev;
-       port->status |= USB_PORT_STAT_CONNECTION;
-       port->change |= USB_PORT_STAT_C_CONNECTION;
-       /* Now the port status changed to connected; hub_wq will
-        * pick the change up and try to reset the port to bring it to
-        * the enabled state--so this process returns up to the stack
-        * and it calls back into wusbhc_rh_port_reset().
-        */
-error_unlock:
-       mutex_unlock(&wusbhc->mutex);
-       return;
-
-}
-
-/*
- * Disconnect a Wireless USB device from its fake port
- *
- * Marks the port as disconnected so that hub_wq can pick up the change
- * and drops our knowledge about the device.
- *
- * Assumes there is a device connected
- *
- * @port_index: zero based port number
- *
- * NOTE: @wusbhc->mutex is locked
- *
- * WARNING: From here it is not very safe to access anything hanging off
- *         wusb_dev
- */
-static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc,
-                                   struct wusb_port *port)
-{
-       struct wusb_dev *wusb_dev = port->wusb_dev;
-
-       port->status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE
-                         | USB_PORT_STAT_SUSPEND | USB_PORT_STAT_RESET
-                         | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
-       port->change |= USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE;
-       if (wusb_dev) {
-               dev_dbg(wusbhc->dev, "disconnecting device from port %d\n", wusb_dev->port_idx);
-               if (!list_empty(&wusb_dev->cack_node))
-                       list_del_init(&wusb_dev->cack_node);
-               /* For the one in cack_add() */
-               wusb_dev_put(wusb_dev);
-       }
-       port->wusb_dev = NULL;
-
-       /* After a device disconnects, change the GTK (see [WUSB]
-        * section 6.2.11.2). */
-       if (wusbhc->active)
-               wusbhc_gtk_rekey(wusbhc);
-
-       /* The Wireless USB part has forgotten about the device already; now
-        * hub_wq's timer will pick up the disconnection and remove the USB
-        * device from the system
-        */
-}
-
-/*
- * Refresh the list of keep alives to emit in the MMC
- *
- * We only publish the first four devices that have a coming timeout
- * condition. Then when we are done processing those, we go for the
- * next ones. We ignore the ones that have timed out already (they'll
- * be purged).
- *
- * This might cause the first devices to timeout the last devices in
- * the port array...FIXME: come up with a better algorithm?
- *
- * Note we can't do much about MMC's ops errors; we hope next refresh
- * will kind of handle it.
- *
- * NOTE: @wusbhc->mutex is locked
- */
-static void __wusbhc_keep_alive(struct wusbhc *wusbhc)
-{
-       struct device *dev = wusbhc->dev;
-       unsigned cnt;
-       struct wusb_dev *wusb_dev;
-       struct wusb_port *wusb_port;
-       struct wuie_keep_alive *ie = &wusbhc->keep_alive_ie;
-       unsigned keep_alives, old_keep_alives;
-
-       old_keep_alives = ie->hdr.bLength - sizeof(ie->hdr);
-       keep_alives = 0;
-       for (cnt = 0;
-            keep_alives < WUIE_ELT_MAX && cnt < wusbhc->ports_max;
-            cnt++) {
-               unsigned tt = msecs_to_jiffies(wusbhc->trust_timeout);
-
-               wusb_port = wusb_port_by_idx(wusbhc, cnt);
-               wusb_dev = wusb_port->wusb_dev;
-
-               if (wusb_dev == NULL)
-                       continue;
-               if (wusb_dev->usb_dev == NULL)
-                       continue;
-
-               if (time_after(jiffies, wusb_dev->entry_ts + tt)) {
-                       dev_err(dev, "KEEPALIVE: device %u timed out\n",
-                               wusb_dev->addr);
-                       __wusbhc_dev_disconnect(wusbhc, wusb_port);
-               } else if (time_after(jiffies, wusb_dev->entry_ts + tt/3)) {
-                       /* Approaching timeout cut off, need to refresh */
-                       ie->bDeviceAddress[keep_alives++] = wusb_dev->addr;
-               }
-       }
-       if (keep_alives & 0x1)  /* pad to even number ([WUSB] section 7.5.9) */
-               ie->bDeviceAddress[keep_alives++] = 0x7f;
-       ie->hdr.bLength = sizeof(ie->hdr) +
-               keep_alives*sizeof(ie->bDeviceAddress[0]);
-       if (keep_alives > 0)
-               wusbhc_mmcie_set(wusbhc, 10, 5, &ie->hdr);
-       else if (old_keep_alives != 0)
-               wusbhc_mmcie_rm(wusbhc, &ie->hdr);
-}
-
-/*
- * Do a run through all devices checking for timeouts
- */
-static void wusbhc_keep_alive_run(struct work_struct *ws)
-{
-       struct delayed_work *dw = to_delayed_work(ws);
-       struct wusbhc *wusbhc = container_of(dw, struct wusbhc, keep_alive_timer);
-
-       mutex_lock(&wusbhc->mutex);
-       __wusbhc_keep_alive(wusbhc);
-       mutex_unlock(&wusbhc->mutex);
-
-       queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
-                          msecs_to_jiffies(wusbhc->trust_timeout / 2));
-}
-
-/*
- * Find the wusb_dev from its device address.
- *
- * The device can be found directly from the address (see
- * wusb_cack_add() for where the device address is set to port_idx
- * +2), except when the address is zero.
- */
-static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)
-{
-       int p;
-
-       if (addr == 0xff) /* unconnected */
-               return NULL;
-
-       if (addr > 0) {
-               int port = (addr & ~0x80) - 2;
-               if (port < 0 || port >= wusbhc->ports_max)
-                       return NULL;
-               return wusb_port_by_idx(wusbhc, port)->wusb_dev;
-       }
-
-       /* Look for the device with address 0. */
-       for (p = 0; p < wusbhc->ports_max; p++) {
-               struct wusb_dev *wusb_dev = wusb_port_by_idx(wusbhc, p)->wusb_dev;
-               if (wusb_dev && wusb_dev->addr == addr)
-                       return wusb_dev;
-       }
-       return NULL;
-}
-
-/*
- * Handle a DN_Alive notification (WUSB1.0[7.6.1])
- *
- * This just updates the device activity timestamp and then refreshes
- * the keep alive IE.
- *
- * @wusbhc shall be referenced and unlocked
- */
-static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, u8 srcaddr)
-{
-       struct wusb_dev *wusb_dev;
-
-       mutex_lock(&wusbhc->mutex);
-       wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
-       if (wusb_dev == NULL) {
-               dev_dbg(wusbhc->dev, "ignoring DN_Alive from unconnected device %02x\n",
-                       srcaddr);
-       } else {
-               wusb_dev->entry_ts = jiffies;
-               __wusbhc_keep_alive(wusbhc);
-       }
-       mutex_unlock(&wusbhc->mutex);
-}
-
-/*
- * Handle a DN_Connect notification (WUSB1.0[7.6.1])
- *
- * @wusbhc
- * @pkt_hdr
- * @size:    Size of the buffer where the notification resides; if the
- *           notification data suggests there should be more data than
- *           available, an error will be signaled and the whole buffer
- *           consumed.
- *
- * @wusbhc->mutex shall be held
- */
-static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,
-                                    struct wusb_dn_hdr *dn_hdr,
-                                    size_t size)
-{
-       struct device *dev = wusbhc->dev;
-       struct wusb_dn_connect *dnc;
-       char pr_cdid[WUSB_CKHDID_STRSIZE];
-       static const char *beacon_behaviour[] = {
-               "reserved",
-               "self-beacon",
-               "directed-beacon",
-               "no-beacon"
-       };
-
-       if (size < sizeof(*dnc)) {
-               dev_err(dev, "DN CONNECT: short notification (%zu < %zu)\n",
-                       size, sizeof(*dnc));
-               return;
-       }
-
-       dnc = container_of(dn_hdr, struct wusb_dn_connect, hdr);
-       sprintf(pr_cdid, "%16ph", dnc->CDID.data);
-       dev_info(dev, "DN CONNECT: device %s @ %x (%s) wants to %s\n",
-                pr_cdid,
-                wusb_dn_connect_prev_dev_addr(dnc),
-                beacon_behaviour[wusb_dn_connect_beacon_behavior(dnc)],
-                wusb_dn_connect_new_connection(dnc) ? "connect" : "reconnect");
-       /* ACK the connect */
-       wusbhc_devconnect_ack(wusbhc, dnc, pr_cdid);
-}
-
-/*
- * Handle a DN_Disconnect notification (WUSB1.0[7.6.1])
- *
- * Device is going down -- do the disconnect.
- *
- * @wusbhc shall be referenced and unlocked
- */
-static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, u8 srcaddr)
-{
-       struct device *dev = wusbhc->dev;
-       struct wusb_dev *wusb_dev;
-
-       mutex_lock(&wusbhc->mutex);
-       wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr);
-       if (wusb_dev == NULL) {
-               dev_dbg(dev, "ignoring DN DISCONNECT from unconnected device %02x\n",
-                       srcaddr);
-       } else {
-               dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n",
-                       wusb_dev->addr);
-               __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc,
-                       wusb_dev->port_idx));
-       }
-       mutex_unlock(&wusbhc->mutex);
-}
-
-/*
- * Handle a Device Notification coming a host
- *
- * The Device Notification comes from a host (HWA, DWA or WHCI)
- * wrapped in a set of headers. Somebody else has peeled off those
- * headers for us and we just get one Device Notifications.
- *
- * Invalid DNs (e.g., too short) are discarded.
- *
- * @wusbhc shall be referenced
- *
- * FIXMES:
- *  - implement priorities as in WUSB1.0[Table 7-55]?
- */
-void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr,
-                     struct wusb_dn_hdr *dn_hdr, size_t size)
-{
-       struct device *dev = wusbhc->dev;
-
-       if (size < sizeof(struct wusb_dn_hdr)) {
-               dev_err(dev, "DN data shorter than DN header (%d < %d)\n",
-                       (int)size, (int)sizeof(struct wusb_dn_hdr));
-               return;
-       }
-       switch (dn_hdr->bType) {
-       case WUSB_DN_CONNECT:
-               wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);
-               break;
-       case WUSB_DN_ALIVE:
-               wusbhc_handle_dn_alive(wusbhc, srcaddr);
-               break;
-       case WUSB_DN_DISCONNECT:
-               wusbhc_handle_dn_disconnect(wusbhc, srcaddr);
-               break;
-       case WUSB_DN_MASAVAILCHANGED:
-       case WUSB_DN_RWAKE:
-       case WUSB_DN_SLEEP:
-               /* FIXME: handle these DNs. */
-               break;
-       case WUSB_DN_EPRDY:
-               /* The hardware handles these. */
-               break;
-       default:
-               dev_warn(dev, "unknown DN %u (%d octets) from %u\n",
-                        dn_hdr->bType, (int)size, srcaddr);
-       }
-}
-EXPORT_SYMBOL_GPL(wusbhc_handle_dn);
-
-/*
- * Disconnect a WUSB device from a the cluster
- *
- * @wusbhc
- * @port     Fake port where the device is (wusbhc index, not USB port number).
- *
- * In Wireless USB, a disconnect is basically telling the device he is
- * being disconnected and forgetting about him.
- *
- * We send the device a Device Disconnect IE (WUSB1.0[7.5.11]) for 100
- * ms and then keep going.
- *
- * We don't do much in case of error; we always pretend we disabled
- * the port and disconnected the device. If physically the request
- * didn't get there (many things can fail in the way there), the stack
- * will reject the device's communication attempts.
- *
- * @wusbhc should be refcounted and locked
- */
-void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port_idx)
-{
-       int result;
-       struct device *dev = wusbhc->dev;
-       struct wusb_dev *wusb_dev;
-       struct wuie_disconnect *ie;
-
-       wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
-       if (wusb_dev == NULL) {
-               /* reset no device? ignore */
-               dev_dbg(dev, "DISCONNECT: no device at port %u, ignoring\n",
-                       port_idx);
-               return;
-       }
-       __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
-
-       ie = kzalloc(sizeof(*ie), GFP_KERNEL);
-       if (ie == NULL)
-               return;
-       ie->hdr.bLength = sizeof(*ie);
-       ie->hdr.bIEIdentifier = WUIE_ID_DEVICE_DISCONNECT;
-       ie->bDeviceAddress = wusb_dev->addr;
-       result = wusbhc_mmcie_set(wusbhc, 0, 0, &ie->hdr);
-       if (result < 0)
-               dev_err(dev, "DISCONNECT: can't set MMC: %d\n", result);
-       else {
-               /* At least 6 MMCs, assuming at least 1 MMC per zone. */
-               msleep(7*4);
-               wusbhc_mmcie_rm(wusbhc, &ie->hdr);
-       }
-       kfree(ie);
-}
-
-/*
- * Walk over the BOS descriptor, verify and grok it
- *
- * @usb_dev: referenced
- * @wusb_dev: referenced and unlocked
- *
- * The BOS descriptor is defined at WUSB1.0[7.4.1], and it defines a
- * "flexible" way to wrap all kinds of descriptors inside an standard
- * descriptor (wonder why they didn't use normal descriptors,
- * btw). Not like they lack code.
- *
- * At the end we go to look for the WUSB Device Capabilities
- * (WUSB1.0[7.4.1.1]) that is wrapped in a device capability descriptor
- * that is part of the BOS descriptor set. That tells us what does the
- * device support (dual role, beacon type, UWB PHY rates).
- */
-static int wusb_dev_bos_grok(struct usb_device *usb_dev,
-                            struct wusb_dev *wusb_dev,
-                            struct usb_bos_descriptor *bos, size_t desc_size)
-{
-       ssize_t result;
-       struct device *dev = &usb_dev->dev;
-       void *itr, *top;
-
-       /* Walk over BOS capabilities, verify them */
-       itr = (void *)bos + sizeof(*bos);
-       top = itr + desc_size - sizeof(*bos);
-       while (itr < top) {
-               struct usb_dev_cap_header *cap_hdr = itr;
-               size_t cap_size;
-               u8 cap_type;
-               if (top - itr < sizeof(*cap_hdr)) {
-                       dev_err(dev, "Device BUG? premature end of BOS header "
-                               "data [offset 0x%02x]: only %zu bytes left\n",
-                               (int)(itr - (void *)bos), top - itr);
-                       result = -ENOSPC;
-                       goto error_bad_cap;
-               }
-               cap_size = cap_hdr->bLength;
-               cap_type = cap_hdr->bDevCapabilityType;
-               if (cap_size == 0)
-                       break;
-               if (cap_size > top - itr) {
-                       dev_err(dev, "Device BUG? premature end of BOS data "
-                               "[offset 0x%02x cap %02x %zu bytes]: "
-                               "only %zu bytes left\n",
-                               (int)(itr - (void *)bos),
-                               cap_type, cap_size, top - itr);
-                       result = -EBADF;
-                       goto error_bad_cap;
-               }
-               switch (cap_type) {
-               case USB_CAP_TYPE_WIRELESS_USB:
-                       if (cap_size != sizeof(*wusb_dev->wusb_cap_descr))
-                               dev_err(dev, "Device BUG? WUSB Capability "
-                                       "descriptor is %zu bytes vs %zu "
-                                       "needed\n", cap_size,
-                                       sizeof(*wusb_dev->wusb_cap_descr));
-                       else
-                               wusb_dev->wusb_cap_descr = itr;
-                       break;
-               default:
-                       dev_err(dev, "BUG? Unknown BOS capability 0x%02x "
-                               "(%zu bytes) at offset 0x%02x\n", cap_type,
-                               cap_size, (int)(itr - (void *)bos));
-               }
-               itr += cap_size;
-       }
-       result = 0;
-error_bad_cap:
-       return result;
-}
-
-/*
- * Add information from the BOS descriptors to the device
- *
- * @usb_dev: referenced
- * @wusb_dev: referenced and unlocked
- *
- * So what we do is we alloc a space for the BOS descriptor of 64
- * bytes; read the first four bytes which include the wTotalLength
- * field (WUSB1.0[T7-26]) and if it fits in those 64 bytes, read the
- * whole thing. If not we realloc to that size.
- *
- * Then we call the groking function, that will fill up
- * wusb_dev->wusb_cap_descr, which is what we'll need later on.
- */
-static int wusb_dev_bos_add(struct usb_device *usb_dev,
-                           struct wusb_dev *wusb_dev)
-{
-       ssize_t result;
-       struct device *dev = &usb_dev->dev;
-       struct usb_bos_descriptor *bos;
-       size_t alloc_size = 32, desc_size = 4;
-
-       bos = kmalloc(alloc_size, GFP_KERNEL);
-       if (bos == NULL)
-               return -ENOMEM;
-       result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size);
-       if (result < 4) {
-               dev_err(dev, "Can't get BOS descriptor or too short: %zd\n",
-                       result);
-               goto error_get_descriptor;
-       }
-       desc_size = le16_to_cpu(bos->wTotalLength);
-       if (desc_size >= alloc_size) {
-               kfree(bos);
-               alloc_size = desc_size;
-               bos = kmalloc(alloc_size, GFP_KERNEL);
-               if (bos == NULL)
-                       return -ENOMEM;
-       }
-       result = usb_get_descriptor(usb_dev, USB_DT_BOS, 0, bos, desc_size);
-       if (result < 0 || result != desc_size) {
-               dev_err(dev, "Can't get  BOS descriptor or too short (need "
-                       "%zu bytes): %zd\n", desc_size, result);
-               goto error_get_descriptor;
-       }
-       if (result < sizeof(*bos)
-           || le16_to_cpu(bos->wTotalLength) != desc_size) {
-               dev_err(dev, "Can't get  BOS descriptor or too short (need "
-                       "%zu bytes): %zd\n", desc_size, result);
-               goto error_get_descriptor;
-       }
-
-       result = wusb_dev_bos_grok(usb_dev, wusb_dev, bos, result);
-       if (result < 0)
-               goto error_bad_bos;
-       wusb_dev->bos = bos;
-       return 0;
-
-error_bad_bos:
-error_get_descriptor:
-       kfree(bos);
-       wusb_dev->wusb_cap_descr = NULL;
-       return result;
-}
-
-static void wusb_dev_bos_rm(struct wusb_dev *wusb_dev)
-{
-       kfree(wusb_dev->bos);
-       wusb_dev->wusb_cap_descr = NULL;
-};
-
-/*
- * USB stack's device addition Notifier Callback
- *
- * Called from drivers/usb/core/hub.c when a new device is added; we
- * use this hook to perform certain WUSB specific setup work on the
- * new device. As well, it is the first time we can connect the
- * wusb_dev and the usb_dev. So we note it down in wusb_dev and take a
- * reference that we'll drop.
- *
- * First we need to determine if the device is a WUSB device (else we
- * ignore it). For that we use the speed setting (USB_SPEED_WIRELESS)
- * [FIXME: maybe we'd need something more definitive]. If so, we track
- * it's usb_busd and from there, the WUSB HC.
- *
- * Because all WUSB HCs are contained in a 'struct wusbhc', voila, we
- * get the wusbhc for the device.
- *
- * We have a reference on @usb_dev (as we are called at the end of its
- * enumeration).
- *
- * NOTE: @usb_dev locked
- */
-static void wusb_dev_add_ncb(struct usb_device *usb_dev)
-{
-       int result = 0;
-       struct wusb_dev *wusb_dev;
-       struct wusbhc *wusbhc;
-       struct device *dev = &usb_dev->dev;
-       u8 port_idx;
-
-       if (usb_dev->wusb == 0 || usb_dev->devnum == 1)
-               return;         /* skip non wusb and wusb RHs */
-
-       usb_set_device_state(usb_dev, USB_STATE_UNAUTHENTICATED);
-
-       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
-       if (wusbhc == NULL)
-               goto error_nodev;
-       mutex_lock(&wusbhc->mutex);
-       wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev);
-       port_idx = wusb_port_no_to_idx(usb_dev->portnum);
-       mutex_unlock(&wusbhc->mutex);
-       if (wusb_dev == NULL)
-               goto error_nodev;
-       wusb_dev->usb_dev = usb_get_dev(usb_dev);
-       usb_dev->wusb_dev = wusb_dev_get(wusb_dev);
-       result = wusb_dev_sec_add(wusbhc, usb_dev, wusb_dev);
-       if (result < 0) {
-               dev_err(dev, "Cannot enable security: %d\n", result);
-               goto error_sec_add;
-       }
-       /* Now query the device for it's BOS and attach it to wusb_dev */
-       result = wusb_dev_bos_add(usb_dev, wusb_dev);
-       if (result < 0) {
-               dev_err(dev, "Cannot get BOS descriptors: %d\n", result);
-               goto error_bos_add;
-       }
-       result = wusb_dev_sysfs_add(wusbhc, usb_dev, wusb_dev);
-       if (result < 0)
-               goto error_add_sysfs;
-out:
-       wusb_dev_put(wusb_dev);
-       wusbhc_put(wusbhc);
-error_nodev:
-       return;
-
-error_add_sysfs:
-       wusb_dev_bos_rm(wusb_dev);
-error_bos_add:
-       wusb_dev_sec_rm(wusb_dev);
-error_sec_add:
-       mutex_lock(&wusbhc->mutex);
-       __wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, port_idx));
-       mutex_unlock(&wusbhc->mutex);
-       goto out;
-}
-
-/*
- * Undo all the steps done at connection by the notifier callback
- *
- * NOTE: @usb_dev locked
- */
-static void wusb_dev_rm_ncb(struct usb_device *usb_dev)
-{
-       struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
-
-       if (usb_dev->wusb == 0 || usb_dev->devnum == 1)
-               return;         /* skip non wusb and wusb RHs */
-
-       wusb_dev_sysfs_rm(wusb_dev);
-       wusb_dev_bos_rm(wusb_dev);
-       wusb_dev_sec_rm(wusb_dev);
-       wusb_dev->usb_dev = NULL;
-       usb_dev->wusb_dev = NULL;
-       wusb_dev_put(wusb_dev);
-       usb_put_dev(usb_dev);
-}
-
-/*
- * Handle notifications from the USB stack (notifier call back)
- *
- * This is called when the USB stack does a
- * usb_{bus,device}_{add,remove}() so we can do WUSB specific
- * handling. It is called with [for the case of
- * USB_DEVICE_{ADD,REMOVE} with the usb_dev locked.
- */
-int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,
-                void *priv)
-{
-       int result = NOTIFY_OK;
-
-       switch (val) {
-       case USB_DEVICE_ADD:
-               wusb_dev_add_ncb(priv);
-               break;
-       case USB_DEVICE_REMOVE:
-               wusb_dev_rm_ncb(priv);
-               break;
-       case USB_BUS_ADD:
-               /* ignore (for now) */
-       case USB_BUS_REMOVE:
-               break;
-       default:
-               WARN_ON(1);
-               result = NOTIFY_BAD;
-       }
-       return result;
-}
-
-/*
- * Return a referenced wusb_dev given a @wusbhc and @usb_dev
- */
-struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *wusbhc,
-                                          struct usb_device *usb_dev)
-{
-       struct wusb_dev *wusb_dev;
-       u8 port_idx;
-
-       port_idx = wusb_port_no_to_idx(usb_dev->portnum);
-       BUG_ON(port_idx > wusbhc->ports_max);
-       wusb_dev = wusb_port_by_idx(wusbhc, port_idx)->wusb_dev;
-       if (wusb_dev != NULL)           /* ops, device is gone */
-               wusb_dev_get(wusb_dev);
-       return wusb_dev;
-}
-EXPORT_SYMBOL_GPL(__wusb_dev_get_by_usb_dev);
-
-void wusb_dev_destroy(struct kref *_wusb_dev)
-{
-       struct wusb_dev *wusb_dev = container_of(_wusb_dev, struct wusb_dev, refcnt);
-
-       list_del_init(&wusb_dev->cack_node);
-       wusb_dev_free(wusb_dev);
-}
-EXPORT_SYMBOL_GPL(wusb_dev_destroy);
-
-/*
- * Create all the device connect handling infrastructure
- *
- * This is basically the device info array, Connect Acknowledgement
- * (cack) lists, keep-alive timers (and delayed work thread).
- */
-int wusbhc_devconnect_create(struct wusbhc *wusbhc)
-{
-       wusbhc->keep_alive_ie.hdr.bIEIdentifier = WUIE_ID_KEEP_ALIVE;
-       wusbhc->keep_alive_ie.hdr.bLength = sizeof(wusbhc->keep_alive_ie.hdr);
-       INIT_DELAYED_WORK(&wusbhc->keep_alive_timer, wusbhc_keep_alive_run);
-
-       wusbhc->cack_ie.hdr.bIEIdentifier = WUIE_ID_CONNECTACK;
-       wusbhc->cack_ie.hdr.bLength = sizeof(wusbhc->cack_ie.hdr);
-       INIT_LIST_HEAD(&wusbhc->cack_list);
-
-       return 0;
-}
-
-/*
- * Release all resources taken by the devconnect stuff
- */
-void wusbhc_devconnect_destroy(struct wusbhc *wusbhc)
-{
-       /* no op */
-}
-
-/*
- * wusbhc_devconnect_start - start accepting device connections
- * @wusbhc: the WUSB HC
- *
- * Sets the Host Info IE to accept all new connections.
- *
- * FIXME: This also enables the keep alives but this is not necessary
- * until there are connected and authenticated devices.
- */
-int wusbhc_devconnect_start(struct wusbhc *wusbhc)
-{
-       struct device *dev = wusbhc->dev;
-       struct wuie_host_info *hi;
-       int result;
-
-       hi = kzalloc(sizeof(*hi), GFP_KERNEL);
-       if (hi == NULL)
-               return -ENOMEM;
-
-       hi->hdr.bLength       = sizeof(*hi);
-       hi->hdr.bIEIdentifier = WUIE_ID_HOST_INFO;
-       hi->attributes        = cpu_to_le16((wusbhc->rsv->stream << 3) | WUIE_HI_CAP_ALL);
-       hi->CHID              = wusbhc->chid;
-       result = wusbhc_mmcie_set(wusbhc, 0, 0, &hi->hdr);
-       if (result < 0) {
-               dev_err(dev, "Cannot add Host Info MMCIE: %d\n", result);
-               goto error_mmcie_set;
-       }
-       wusbhc->wuie_host_info = hi;
-
-       queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
-                          msecs_to_jiffies(wusbhc->trust_timeout / 2));
-
-       return 0;
-
-error_mmcie_set:
-       kfree(hi);
-       return result;
-}
-
-/*
- * wusbhc_devconnect_stop - stop managing connected devices
- * @wusbhc: the WUSB HC
- *
- * Disconnects any devices still connected, stops the keep alives and
- * removes the Host Info IE.
- */
-void wusbhc_devconnect_stop(struct wusbhc *wusbhc)
-{
-       int i;
-
-       mutex_lock(&wusbhc->mutex);
-       for (i = 0; i < wusbhc->ports_max; i++) {
-               if (wusbhc->port[i].wusb_dev)
-                       __wusbhc_dev_disconnect(wusbhc, &wusbhc->port[i]);
-       }
-       mutex_unlock(&wusbhc->mutex);
-
-       cancel_delayed_work_sync(&wusbhc->keep_alive_timer);
-       wusbhc_mmcie_rm(wusbhc, &wusbhc->wuie_host_info->hdr);
-       kfree(wusbhc->wuie_host_info);
-       wusbhc->wuie_host_info = NULL;
-}
-
-/*
- * wusb_set_dev_addr - set the WUSB device address used by the host
- * @wusbhc: the WUSB HC the device is connect to
- * @wusb_dev: the WUSB device
- * @addr: new device address
- */
-int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev, u8 addr)
-{
-       int result;
-
-       wusb_dev->addr = addr;
-       result = wusbhc->dev_info_set(wusbhc, wusb_dev);
-       if (result < 0)
-               dev_err(wusbhc->dev, "device %d: failed to set device "
-                       "address\n", wusb_dev->port_idx);
-       else
-               dev_info(wusbhc->dev, "device %d: %s addr %u\n",
-                        wusb_dev->port_idx,
-                        (addr & WUSB_DEV_ADDR_UNAUTH) ? "unauth" : "auth",
-                        wusb_dev->addr);
-
-       return result;
-}
diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c
deleted file mode 100644 (file)
index acce0d5..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
- * MMC (Microscheduled Management Command) handling
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * WUIEs and MMC IEs...well, they are almost the same at the end. MMC
- * IEs are Wireless USB IEs that go into the MMC period...[what is
- * that? look in Design-overview.txt].
- *
- *
- * This is a simple subsystem to keep track of which IEs are being
- * sent by the host in the MMC period.
- *
- * For each WUIE we ask to send, we keep it in an array, so we can
- * request its removal later, or replace the content. They are tracked
- * by pointer, so be sure to use the same pointer if you want to
- * remove it or update the contents.
- *
- * FIXME:
- *  - add timers that autoremove intervalled IEs?
- */
-#include <linux/usb/wusb.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include "wusbhc.h"
-
-/* Initialize the MMCIEs handling mechanism */
-int wusbhc_mmcie_create(struct wusbhc *wusbhc)
-{
-       u8 mmcies = wusbhc->mmcies_max;
-       wusbhc->mmcie = kcalloc(mmcies, sizeof(wusbhc->mmcie[0]), GFP_KERNEL);
-       if (wusbhc->mmcie == NULL)
-               return -ENOMEM;
-       mutex_init(&wusbhc->mmcie_mutex);
-       return 0;
-}
-
-/* Release resources used by the MMCIEs handling mechanism */
-void wusbhc_mmcie_destroy(struct wusbhc *wusbhc)
-{
-       kfree(wusbhc->mmcie);
-}
-
-/*
- * Add or replace an MMC Wireless USB IE.
- *
- * @interval:    See WUSB1.0[8.5.3.1]
- * @repeat_cnt:  See WUSB1.0[8.5.3.1]
- * @handle:      See WUSB1.0[8.5.3.1]
- * @wuie:        Pointer to the header of the WUSB IE data to add.
- *               MUST BE allocated in a kmalloc buffer (no stack or
- *               vmalloc).
- *               THE CALLER ALWAYS OWNS THE POINTER (we don't free it
- *               on remove, we just forget about it).
- * @returns:     0 if ok, < 0 errno code on error.
- *
- * Goes over the *whole* @wusbhc->mmcie array looking for (a) the
- * first free spot and (b) if @wuie is already in the array (aka:
- * transmitted in the MMCs) the spot were it is.
- *
- * If present, we "overwrite it" (update).
- *
- *
- * NOTE: Need special ordering rules -- see below WUSB1.0 Table 7-38.
- *       The host uses the handle as the 'sort' index. We
- *       allocate the last one always for the WUIE_ID_HOST_INFO, and
- *       the rest, first come first serve in inverse order.
- *
- *       Host software must make sure that it adds the other IEs in
- *       the right order... the host hardware is responsible for
- *       placing the WCTA IEs in the right place with the other IEs
- *       set by host software.
- *
- * NOTE: we can access wusbhc->wa_descr without locking because it is
- *       read only.
- */
-int wusbhc_mmcie_set(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
-                    struct wuie_hdr *wuie)
-{
-       int result = -ENOBUFS;
-       unsigned handle, itr;
-
-       /* Search a handle, taking into account the ordering */
-       mutex_lock(&wusbhc->mmcie_mutex);
-       switch (wuie->bIEIdentifier) {
-       case WUIE_ID_HOST_INFO:
-               /* Always last */
-               handle = wusbhc->mmcies_max - 1;
-               break;
-       case WUIE_ID_ISOCH_DISCARD:
-               dev_err(wusbhc->dev, "Special ordering case for WUIE ID 0x%x "
-                       "unimplemented\n", wuie->bIEIdentifier);
-               result = -ENOSYS;
-               goto error_unlock;
-       default:
-               /* search for it or find the last empty slot */
-               handle = ~0;
-               for (itr = 0; itr < wusbhc->mmcies_max - 1; itr++) {
-                       if (wusbhc->mmcie[itr] == wuie) {
-                               handle = itr;
-                               break;
-                       }
-                       if (wusbhc->mmcie[itr] == NULL)
-                               handle = itr;
-               }
-               if (handle == ~0)
-                       goto error_unlock;
-       }
-       result = (wusbhc->mmcie_add)(wusbhc, interval, repeat_cnt, handle,
-                                    wuie);
-       if (result >= 0)
-               wusbhc->mmcie[handle] = wuie;
-error_unlock:
-       mutex_unlock(&wusbhc->mmcie_mutex);
-       return result;
-}
-EXPORT_SYMBOL_GPL(wusbhc_mmcie_set);
-
-/*
- * Remove an MMC IE previously added with wusbhc_mmcie_set()
- *
- * @wuie       Pointer used to add the WUIE
- */
-void wusbhc_mmcie_rm(struct wusbhc *wusbhc, struct wuie_hdr *wuie)
-{
-       int result;
-       unsigned handle, itr;
-
-       mutex_lock(&wusbhc->mmcie_mutex);
-       for (itr = 0; itr < wusbhc->mmcies_max; itr++) {
-               if (wusbhc->mmcie[itr] == wuie) {
-                       handle = itr;
-                       goto found;
-               }
-       }
-       mutex_unlock(&wusbhc->mmcie_mutex);
-       return;
-
-found:
-       result = (wusbhc->mmcie_rm)(wusbhc, handle);
-       if (result == 0)
-               wusbhc->mmcie[itr] = NULL;
-       mutex_unlock(&wusbhc->mmcie_mutex);
-}
-EXPORT_SYMBOL_GPL(wusbhc_mmcie_rm);
-
-static int wusbhc_mmc_start(struct wusbhc *wusbhc)
-{
-       int ret;
-
-       mutex_lock(&wusbhc->mutex);
-       ret = wusbhc->start(wusbhc);
-       if (ret >= 0)
-               wusbhc->active = 1;
-       mutex_unlock(&wusbhc->mutex);
-
-       return ret;
-}
-
-static void wusbhc_mmc_stop(struct wusbhc *wusbhc)
-{
-       mutex_lock(&wusbhc->mutex);
-       wusbhc->active = 0;
-       wusbhc->stop(wusbhc, WUSB_CHANNEL_STOP_DELAY_MS);
-       mutex_unlock(&wusbhc->mutex);
-}
-
-/*
- * wusbhc_start - start transmitting MMCs and accepting connections
- * @wusbhc: the HC to start
- *
- * Establishes a cluster reservation, enables device connections, and
- * starts MMCs with appropriate DNTS parameters.
- */
-int wusbhc_start(struct wusbhc *wusbhc)
-{
-       int result;
-       struct device *dev = wusbhc->dev;
-
-       WARN_ON(wusbhc->wuie_host_info != NULL);
-       BUG_ON(wusbhc->uwb_rc == NULL);
-
-       result = wusbhc_rsv_establish(wusbhc);
-       if (result < 0) {
-               dev_err(dev, "cannot establish cluster reservation: %d\n",
-                       result);
-               goto error_rsv_establish;
-       }
-
-       result = wusbhc_devconnect_start(wusbhc);
-       if (result < 0) {
-               dev_err(dev, "error enabling device connections: %d\n",
-                       result);
-               goto error_devconnect_start;
-       }
-
-       result = wusbhc_sec_start(wusbhc);
-       if (result < 0) {
-               dev_err(dev, "error starting security in the HC: %d\n",
-                       result);
-               goto error_sec_start;
-       }
-
-       result = wusbhc->set_num_dnts(wusbhc, wusbhc->dnts_interval,
-               wusbhc->dnts_num_slots);
-       if (result < 0) {
-               dev_err(dev, "Cannot set DNTS parameters: %d\n", result);
-               goto error_set_num_dnts;
-       }
-       result = wusbhc_mmc_start(wusbhc);
-       if (result < 0) {
-               dev_err(dev, "error starting wusbch: %d\n", result);
-               goto error_wusbhc_start;
-       }
-
-       return 0;
-
-error_wusbhc_start:
-       wusbhc_sec_stop(wusbhc);
-error_set_num_dnts:
-error_sec_start:
-       wusbhc_devconnect_stop(wusbhc);
-error_devconnect_start:
-       wusbhc_rsv_terminate(wusbhc);
-error_rsv_establish:
-       return result;
-}
-
-/*
- * wusbhc_stop - stop transmitting MMCs
- * @wusbhc: the HC to stop
- *
- * Stops the WUSB channel and removes the cluster reservation.
- */
-void wusbhc_stop(struct wusbhc *wusbhc)
-{
-       wusbhc_mmc_stop(wusbhc);
-       wusbhc_sec_stop(wusbhc);
-       wusbhc_devconnect_stop(wusbhc);
-       wusbhc_rsv_terminate(wusbhc);
-}
-
-/*
- * Set/reset/update a new CHID
- *
- * Depending on the previous state of the MMCs, start, stop or change
- * the sent MMC. This effectively switches the host controller on and
- * off (radio wise).
- */
-int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
-{
-       int result = 0;
-
-       if (memcmp(chid, &wusb_ckhdid_zero, sizeof(*chid)) == 0)
-               chid = NULL;
-
-       mutex_lock(&wusbhc->mutex);
-       if (chid) {
-               if (wusbhc->active) {
-                       mutex_unlock(&wusbhc->mutex);
-                       return -EBUSY;
-               }
-               wusbhc->chid = *chid;
-       }
-
-       /* register with UWB if we haven't already since we are about to start
-           the radio. */
-       if ((chid) && (wusbhc->uwb_rc == NULL)) {
-               wusbhc->uwb_rc = uwb_rc_get_by_grandpa(wusbhc->dev->parent);
-               if (wusbhc->uwb_rc == NULL) {
-                       result = -ENODEV;
-                       dev_err(wusbhc->dev,
-                               "Cannot get associated UWB Host Controller\n");
-                       goto error_rc_get;
-               }
-
-               result = wusbhc_pal_register(wusbhc);
-               if (result < 0) {
-                       dev_err(wusbhc->dev, "Cannot register as a UWB PAL\n");
-                       goto error_pal_register;
-               }
-       }
-       mutex_unlock(&wusbhc->mutex);
-
-       if (chid)
-               result = uwb_radio_start(&wusbhc->pal);
-       else if (wusbhc->uwb_rc)
-               uwb_radio_stop(&wusbhc->pal);
-
-       return result;
-
-error_pal_register:
-       uwb_rc_put(wusbhc->uwb_rc);
-       wusbhc->uwb_rc = NULL;
-error_rc_get:
-       mutex_unlock(&wusbhc->mutex);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(wusbhc_chid_set);
diff --git a/drivers/usb/wusbcore/pal.c b/drivers/usb/wusbcore/pal.c
deleted file mode 100644 (file)
index 30f5691..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Host Controller
- * UWB Protocol Adaptation Layer (PAL) glue.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include "wusbhc.h"
-
-static void wusbhc_channel_changed(struct uwb_pal *pal, int channel)
-{
-       struct wusbhc *wusbhc = container_of(pal, struct wusbhc, pal);
-
-       dev_dbg(wusbhc->dev, "%s: channel = %d\n", __func__, channel);
-       if (channel < 0)
-               wusbhc_stop(wusbhc);
-       else
-               wusbhc_start(wusbhc);
-}
-
-/**
- * wusbhc_pal_register - register the WUSB HC as a UWB PAL
- * @wusbhc: the WUSB HC
- */
-int wusbhc_pal_register(struct wusbhc *wusbhc)
-{
-       uwb_pal_init(&wusbhc->pal);
-
-       wusbhc->pal.name   = "wusbhc";
-       wusbhc->pal.device = wusbhc->usb_hcd.self.controller;
-       wusbhc->pal.rc     = wusbhc->uwb_rc;
-       wusbhc->pal.channel_changed = wusbhc_channel_changed;
-
-       return uwb_pal_register(&wusbhc->pal);
-}
-
-/**
- * wusbhc_pal_unregister - unregister the WUSB HC as a UWB PAL
- * @wusbhc: the WUSB HC
- */
-void wusbhc_pal_unregister(struct wusbhc *wusbhc)
-{
-       if (wusbhc->uwb_rc)
-               uwb_pal_unregister(&wusbhc->pal);
-}
diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c
deleted file mode 100644 (file)
index 6dcfc68..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB cluster reservation management
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/uwb.h>
-
-#include "wusbhc.h"
-
-/*
- * WUSB cluster reservations are multicast reservations with the
- * broadcast cluster ID (BCID) as the target DevAddr.
- *
- * FIXME: consider adjusting the reservation depending on what devices
- * are attached.
- */
-
-static int wusbhc_bwa_set(struct wusbhc *wusbhc, u8 stream,
-       const struct uwb_mas_bm *mas)
-{
-       if (mas == NULL)
-               mas = &uwb_mas_bm_zero;
-       return wusbhc->bwa_set(wusbhc, stream, mas);
-}
-
-/**
- * wusbhc_rsv_complete_cb - WUSB HC reservation complete callback
- * @rsv:    the reservation
- *
- * Either set or clear the HC's view of the reservation.
- *
- * FIXME: when a reservation is denied the HC should be stopped.
- */
-static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv)
-{
-       struct wusbhc *wusbhc = rsv->pal_priv;
-       struct device *dev = wusbhc->dev;
-       struct uwb_mas_bm mas;
-
-       dev_dbg(dev, "%s: state = %d\n", __func__, rsv->state);
-       switch (rsv->state) {
-       case UWB_RSV_STATE_O_ESTABLISHED:
-               uwb_rsv_get_usable_mas(rsv, &mas);
-               dev_dbg(dev, "established reservation: %*pb\n",
-                       UWB_NUM_MAS, mas.bm);
-               wusbhc_bwa_set(wusbhc, rsv->stream, &mas);
-               break;
-       case UWB_RSV_STATE_NONE:
-               dev_dbg(dev, "removed reservation\n");
-               wusbhc_bwa_set(wusbhc, 0, NULL);
-               break;
-       default:
-               dev_dbg(dev, "unexpected reservation state: %d\n", rsv->state);
-               break;
-       }
-}
-
-
-/**
- * wusbhc_rsv_establish - establish a reservation for the cluster
- * @wusbhc: the WUSB HC requesting a bandwidth reservation
- */
-int wusbhc_rsv_establish(struct wusbhc *wusbhc)
-{
-       struct uwb_rc *rc = wusbhc->uwb_rc;
-       struct uwb_rsv *rsv;
-       struct uwb_dev_addr bcid;
-       int ret;
-
-       if (rc == NULL)
-               return -ENODEV;
-
-       rsv = uwb_rsv_create(rc, wusbhc_rsv_complete_cb, wusbhc);
-       if (rsv == NULL)
-               return -ENOMEM;
-
-       bcid.data[0] = wusbhc->cluster_id;
-       bcid.data[1] = 0;
-
-       rsv->target.type = UWB_RSV_TARGET_DEVADDR;
-       rsv->target.devaddr = bcid;
-       rsv->type = UWB_DRP_TYPE_PRIVATE;
-       rsv->max_mas = 256; /* try to get as much as possible */
-       rsv->min_mas = 15;  /* one MAS per zone */
-       rsv->max_interval = 1; /* max latency is one zone */
-       rsv->is_multicast = true;
-
-       ret = uwb_rsv_establish(rsv);
-       if (ret == 0)
-               wusbhc->rsv = rsv;
-       else
-               uwb_rsv_destroy(rsv);
-       return ret;
-}
-
-
-/**
- * wusbhc_rsv_terminate - terminate the cluster reservation
- * @wusbhc: the WUSB host whose reservation is to be terminated
- */
-void wusbhc_rsv_terminate(struct wusbhc *wusbhc)
-{
-       if (wusbhc->rsv) {
-               uwb_rsv_terminate(wusbhc->rsv);
-               uwb_rsv_destroy(wusbhc->rsv);
-               wusbhc->rsv = NULL;
-       }
-}
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c
deleted file mode 100644 (file)
index 20c08cd..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Host Controller
- * Root Hub operations
- *
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * We fake a root hub that has fake ports (as many as simultaneous
- * devices the Wireless USB Host Controller can deal with). For each
- * port we keep an state in @wusbhc->port[index] identical to the one
- * specified in the USB2.0[ch11] spec and some extra device
- * information that complements the one in 'struct usb_device' (as
- * this lacs a hcpriv pointer).
- *
- * Note this is common to WHCI and HWA host controllers.
- *
- * Through here we enable most of the state changes that the USB stack
- * will use to connect or disconnect devices. We need to do some
- * forced adaptation of Wireless USB device states vs. wired:
- *
- *        USB:                 WUSB:
- *
- * Port   Powered-off          port slot n/a
- *        Powered-on           port slot available
- *        Disconnected         port slot available
- *        Connected            port slot assigned device
- *                            device sent DN_Connect
- *                             device was authenticated
- *        Enabled              device is authenticated, transitioned
- *                             from unauth -> auth -> default address
- *                             -> enabled
- *        Reset                disconnect
- *        Disable              disconnect
- *
- * This maps the standard USB port states with the WUSB device states
- * so we can fake ports without having to modify the USB stack.
- *
- * FIXME: this process will change in the future
- *
- *
- * ENTRY POINTS
- *
- * Our entry points into here are, as in hcd.c, the USB stack root hub
- * ops defined in the usb_hcd struct:
- *
- * wusbhc_rh_status_data()     Provide hub and port status data bitmap
- *
- * wusbhc_rh_control()          Execution of all the major requests
- *                              you can do to a hub (Set|Clear
- *                              features, get descriptors, status, etc).
- *
- * wusbhc_rh_[suspend|resume]() That
- *
- * wusbhc_rh_start_port_reset() ??? unimplemented
- */
-#include <linux/slab.h>
-#include <linux/export.h>
-#include "wusbhc.h"
-
-/*
- * Reset a fake port
- *
- * Using a Reset Device IE is too heavyweight as it causes the device
- * to enter the UnConnected state and leave the cluster, this can mean
- * that when the device reconnects it is connected to a different fake
- * port.
- *
- * Instead, reset authenticated devices with a SetAddress(0), followed
- * by a SetAddresss(AuthAddr).
- *
- * For unauthenticated devices just pretend to reset but do nothing.
- * If the device initialization continues to fail it will eventually
- * time out after TrustTimeout and enter the UnConnected state.
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- *
- * Supposedly we are the only thread accesing @wusbhc->port; in any
- * case, maybe we should move the mutex locking from
- * wusbhc_devconnect_auth() to here.
- *
- * @port_idx refers to the wusbhc's port index, not the USB port number
- */
-static int wusbhc_rh_port_reset(struct wusbhc *wusbhc, u8 port_idx)
-{
-       int result = 0;
-       struct wusb_port *port = wusb_port_by_idx(wusbhc, port_idx);
-       struct wusb_dev *wusb_dev = port->wusb_dev;
-
-       if (wusb_dev == NULL)
-               return -ENOTCONN;
-
-       port->status |= USB_PORT_STAT_RESET;
-       port->change |= USB_PORT_STAT_C_RESET;
-
-       if (wusb_dev->addr & WUSB_DEV_ADDR_UNAUTH)
-               result = 0;
-       else
-               result = wusb_dev_update_address(wusbhc, wusb_dev);
-
-       port->status &= ~USB_PORT_STAT_RESET;
-       port->status |= USB_PORT_STAT_ENABLE;
-       port->change |= USB_PORT_STAT_C_RESET | USB_PORT_STAT_C_ENABLE; 
-
-       return result;
-}
-
-/*
- * Return the hub change status bitmap
- *
- * The bits in the change status bitmap are cleared when a
- * ClearPortFeature request is issued (USB2.0[11.12.3,11.12.4].
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- *
- * WARNING!! This gets called from atomic context; we cannot get the
- *           mutex--the only race condition we can find is some bit
- *           changing just after we copy it, which shouldn't be too
- *           big of a problem [and we can't make it an spinlock
- *           because other parts need to take it and sleep] .
- *
- *           @usb_hcd is refcounted, so it won't disappear under us
- *           and before killing a host, the polling of the root hub
- *           would be stopped anyway.
- */
-int wusbhc_rh_status_data(struct usb_hcd *usb_hcd, char *_buf)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       size_t cnt, size, bits_set = 0;
-
-       /* WE DON'T LOCK, see comment */
-       /* round up to bytes.  Hub bit is bit 0 so add 1. */
-       size = DIV_ROUND_UP(wusbhc->ports_max + 1, 8);
-
-       /* clear the output buffer. */
-       memset(_buf, 0, size);
-       /* set the bit for each changed port. */
-       for (cnt = 0; cnt < wusbhc->ports_max; cnt++) {
-
-               if (wusb_port_by_idx(wusbhc, cnt)->change) {
-                       const int bitpos = cnt+1;
-
-                       _buf[bitpos/8] |= (1 << (bitpos % 8));
-                       bits_set++;
-               }
-       }
-
-       return bits_set ? size : 0;
-}
-EXPORT_SYMBOL_GPL(wusbhc_rh_status_data);
-
-/*
- * Return the hub's descriptor
- *
- * NOTE: almost cut and paste from ehci-hub.c
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked
- */
-static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue,
-                                  u16 wIndex,
-                                  struct usb_hub_descriptor *descr,
-                                  u16 wLength)
-{
-       u16 temp = 1 + (wusbhc->ports_max / 8);
-       u8 length = 7 + 2 * temp;
-
-       if (wLength < length)
-               return -ENOSPC;
-       descr->bDescLength = 7 + 2 * temp;
-       descr->bDescriptorType = USB_DT_HUB; /* HUB type */
-       descr->bNbrPorts = wusbhc->ports_max;
-       descr->wHubCharacteristics = cpu_to_le16(
-               HUB_CHAR_COMMON_LPSM    /* All ports power at once */
-               | 0x00                  /* not part of compound device */
-               | HUB_CHAR_NO_OCPM      /* No overcurrent protection */
-               | 0x00                  /* 8 FS think time FIXME ?? */
-               | 0x00);                /* No port indicators */
-       descr->bPwrOn2PwrGood = 0;
-       descr->bHubContrCurrent = 0;
-       /* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
-       memset(&descr->u.hs.DeviceRemovable[0], 0, temp);
-       memset(&descr->u.hs.DeviceRemovable[temp], 0xff, temp);
-       return 0;
-}
-
-/*
- * Clear a hub feature
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- *
- * Nothing to do, so no locking needed ;)
- */
-static int wusbhc_rh_clear_hub_feat(struct wusbhc *wusbhc, u16 feature)
-{
-       int result;
-
-       switch (feature) {
-       case C_HUB_LOCAL_POWER:
-               /* FIXME: maybe plug bit 0 to the power input status,
-                * if any?
-                * see wusbhc_rh_get_hub_status() */
-       case C_HUB_OVER_CURRENT:
-               result = 0;
-               break;
-       default:
-               result = -EPIPE;
-       }
-       return result;
-}
-
-/*
- * Return hub status (it is always zero...)
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- *
- * Nothing to do, so no locking needed ;)
- */
-static int wusbhc_rh_get_hub_status(struct wusbhc *wusbhc, u32 *buf,
-                                   u16 wLength)
-{
-       /* FIXME: maybe plug bit 0 to the power input status (if any)? */
-       *buf = 0;
-       return 0;
-}
-
-/*
- * Set a port feature
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- */
-static int wusbhc_rh_set_port_feat(struct wusbhc *wusbhc, u16 feature,
-                                  u8 selector, u8 port_idx)
-{
-       struct device *dev = wusbhc->dev;
-
-       if (port_idx > wusbhc->ports_max)
-               return -EINVAL;
-
-       switch (feature) {
-               /* According to USB2.0[11.24.2.13]p2, these features
-                * are not required to be implemented. */
-       case USB_PORT_FEAT_C_OVER_CURRENT:
-       case USB_PORT_FEAT_C_ENABLE:
-       case USB_PORT_FEAT_C_SUSPEND:
-       case USB_PORT_FEAT_C_CONNECTION:
-       case USB_PORT_FEAT_C_RESET:
-               return 0;
-       case USB_PORT_FEAT_POWER:
-               /* No such thing, but we fake it works */
-               mutex_lock(&wusbhc->mutex);
-               wusb_port_by_idx(wusbhc, port_idx)->status |= USB_PORT_STAT_POWER;
-               mutex_unlock(&wusbhc->mutex);
-               return 0;
-       case USB_PORT_FEAT_RESET:
-               return wusbhc_rh_port_reset(wusbhc, port_idx);
-       case USB_PORT_FEAT_ENABLE:
-       case USB_PORT_FEAT_SUSPEND:
-               dev_err(dev, "(port_idx %d) set feat %d/%d UNIMPLEMENTED\n",
-                       port_idx, feature, selector);
-               return -ENOSYS;
-       default:
-               dev_err(dev, "(port_idx %d) set feat %d/%d UNKNOWN\n",
-                       port_idx, feature, selector);
-               return -EPIPE;
-       }
-
-       return 0;
-}
-
-/*
- * Clear a port feature...
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- */
-static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature,
-                                    u8 selector, u8 port_idx)
-{
-       int result = 0;
-       struct device *dev = wusbhc->dev;
-
-       if (port_idx > wusbhc->ports_max)
-               return -EINVAL;
-
-       mutex_lock(&wusbhc->mutex);
-       switch (feature) {
-       case USB_PORT_FEAT_POWER:       /* fake port always on */
-               /* According to USB2.0[11.24.2.7.1.4], no need to implement? */
-       case USB_PORT_FEAT_C_OVER_CURRENT:
-               break;
-       case USB_PORT_FEAT_C_RESET:
-               wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_RESET;
-               break;
-       case USB_PORT_FEAT_C_CONNECTION:
-               wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_CONNECTION;
-               break;
-       case USB_PORT_FEAT_ENABLE:
-               __wusbhc_dev_disable(wusbhc, port_idx);
-               break;
-       case USB_PORT_FEAT_C_ENABLE:
-               wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_ENABLE;
-               break;
-       case USB_PORT_FEAT_SUSPEND:
-       case USB_PORT_FEAT_C_SUSPEND:
-               dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n",
-                       port_idx, feature, selector);
-               result = -ENOSYS;
-               break;
-       default:
-               dev_err(dev, "(port_idx %d) Clear feat %d/%d UNKNOWN\n",
-                       port_idx, feature, selector);
-               result = -EPIPE;
-               break;
-       }
-       mutex_unlock(&wusbhc->mutex);
-
-       return result;
-}
-
-/*
- * Return the port's status
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- */
-static int wusbhc_rh_get_port_status(struct wusbhc *wusbhc, u16 port_idx,
-                                    u32 *_buf, u16 wLength)
-{
-       __le16 *buf = (__le16 *)_buf;
-
-       if (port_idx > wusbhc->ports_max)
-               return -EINVAL;
-
-       mutex_lock(&wusbhc->mutex);
-       buf[0] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->status);
-       buf[1] = cpu_to_le16(wusb_port_by_idx(wusbhc, port_idx)->change);
-       mutex_unlock(&wusbhc->mutex);
-
-       return 0;
-}
-
-/*
- * Entry point for Root Hub operations
- *
- * @wusbhc is assumed referenced and @wusbhc->mutex unlocked.
- */
-int wusbhc_rh_control(struct usb_hcd *usb_hcd, u16 reqntype, u16 wValue,
-                     u16 wIndex, char *buf, u16 wLength)
-{
-       int result = -ENOSYS;
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-
-       switch (reqntype) {
-       case GetHubDescriptor:
-               result = wusbhc_rh_get_hub_descr(
-                       wusbhc, wValue, wIndex,
-                       (struct usb_hub_descriptor *) buf, wLength);
-               break;
-       case ClearHubFeature:
-               result = wusbhc_rh_clear_hub_feat(wusbhc, wValue);
-               break;
-       case GetHubStatus:
-               result = wusbhc_rh_get_hub_status(wusbhc, (u32 *)buf, wLength);
-               break;
-
-       case SetPortFeature:
-               result = wusbhc_rh_set_port_feat(wusbhc, wValue, wIndex >> 8,
-                                                (wIndex & 0xff) - 1);
-               break;
-       case ClearPortFeature:
-               result = wusbhc_rh_clear_port_feat(wusbhc, wValue, wIndex >> 8,
-                                                  (wIndex & 0xff) - 1);
-               break;
-       case GetPortStatus:
-               result = wusbhc_rh_get_port_status(wusbhc, wIndex - 1,
-                                                  (u32 *)buf, wLength);
-               break;
-
-       case SetHubFeature:
-       default:
-               dev_err(wusbhc->dev, "%s (%p [%p], %x, %x, %x, %p, %x) "
-                       "UNIMPLEMENTED\n", __func__, usb_hcd, wusbhc, reqntype,
-                       wValue, wIndex, buf, wLength);
-               /* dump_stack(); */
-               result = -ENOSYS;
-       }
-       return result;
-}
-EXPORT_SYMBOL_GPL(wusbhc_rh_control);
-
-int wusbhc_rh_start_port_reset(struct usb_hcd *usb_hcd, unsigned port_idx)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       dev_err(wusbhc->dev, "%s (%p [%p], port_idx %u) UNIMPLEMENTED\n",
-               __func__, usb_hcd, wusbhc, port_idx);
-       WARN_ON(1);
-       return -ENOSYS;
-}
-EXPORT_SYMBOL_GPL(wusbhc_rh_start_port_reset);
-
-static void wusb_port_init(struct wusb_port *port)
-{
-       port->status |= USB_PORT_STAT_HIGH_SPEED;
-}
-
-/*
- * Alloc fake port specific fields and status.
- */
-int wusbhc_rh_create(struct wusbhc *wusbhc)
-{
-       int result = -ENOMEM;
-       size_t port_size, itr;
-       port_size = wusbhc->ports_max * sizeof(wusbhc->port[0]);
-       wusbhc->port = kzalloc(port_size, GFP_KERNEL);
-       if (wusbhc->port == NULL)
-               goto error_port_alloc;
-       for (itr = 0; itr < wusbhc->ports_max; itr++)
-               wusb_port_init(&wusbhc->port[itr]);
-       result = 0;
-error_port_alloc:
-       return result;
-}
-
-void wusbhc_rh_destroy(struct wusbhc *wusbhc)
-{
-       kfree(wusbhc->port);
-}
diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c
deleted file mode 100644 (file)
index 14ac8c9..0000000
+++ /dev/null
@@ -1,599 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Host Controller
- * Security support: encryption enablement, etc
- *
- * Copyright (C) 2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- */
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/usb/ch9.h>
-#include <linux/random.h>
-#include <linux/export.h>
-#include "wusbhc.h"
-#include <asm/unaligned.h>
-
-static void wusbhc_gtk_rekey_work(struct work_struct *work);
-
-int wusbhc_sec_create(struct wusbhc *wusbhc)
-{
-       /*
-        * WQ is singlethread because we need to serialize rekey operations.
-        * Use a separate workqueue for security operations instead of the
-        * wusbd workqueue because security operations may need to communicate
-        * directly with downstream wireless devices using synchronous URBs.
-        * If a device is not responding, this could block other host
-        * controller operations.
-        */
-       wusbhc->wq_security = create_singlethread_workqueue("wusbd_security");
-       if (wusbhc->wq_security == NULL) {
-               pr_err("WUSB-core: Cannot create wusbd_security workqueue\n");
-               return -ENOMEM;
-       }
-
-       wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) +
-               sizeof(wusbhc->gtk.data);
-       wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY;
-       wusbhc->gtk.descr.bReserved = 0;
-       wusbhc->gtk_index = 0;
-
-       INIT_WORK(&wusbhc->gtk_rekey_work, wusbhc_gtk_rekey_work);
-
-       return 0;
-}
-
-
-/* Called when the HC is destroyed */
-void wusbhc_sec_destroy(struct wusbhc *wusbhc)
-{
-       destroy_workqueue(wusbhc->wq_security);
-}
-
-
-/**
- * wusbhc_next_tkid - generate a new, currently unused, TKID
- * @wusbhc:   the WUSB host controller
- * @wusb_dev: the device whose PTK the TKID is for
- *            (or NULL for a TKID for a GTK)
- *
- * The generated TKID consists of two parts: the device's authenticated
- * address (or 0 or a GTK); and an incrementing number.  This ensures
- * that TKIDs cannot be shared between devices and by the time the
- * incrementing number wraps around the older TKIDs will no longer be
- * in use (a maximum of two keys may be active at any one time).
- */
-static u32 wusbhc_next_tkid(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       u32 *tkid;
-       u32 addr;
-
-       if (wusb_dev == NULL) {
-               tkid = &wusbhc->gtk_tkid;
-               addr = 0;
-       } else {
-               tkid = &wusb_port_by_idx(wusbhc, wusb_dev->port_idx)->ptk_tkid;
-               addr = wusb_dev->addr & 0x7f;
-       }
-
-       *tkid = (addr << 8) | ((*tkid + 1) & 0xff);
-
-       return *tkid;
-}
-
-static void wusbhc_generate_gtk(struct wusbhc *wusbhc)
-{
-       const size_t key_size = sizeof(wusbhc->gtk.data);
-       u32 tkid;
-
-       tkid = wusbhc_next_tkid(wusbhc, NULL);
-
-       wusbhc->gtk.descr.tTKID[0] = (tkid >>  0) & 0xff;
-       wusbhc->gtk.descr.tTKID[1] = (tkid >>  8) & 0xff;
-       wusbhc->gtk.descr.tTKID[2] = (tkid >> 16) & 0xff;
-
-       get_random_bytes(wusbhc->gtk.descr.bKeyData, key_size);
-}
-
-/**
- * wusbhc_sec_start - start the security management process
- * @wusbhc: the WUSB host controller
- *
- * Generate and set an initial GTK on the host controller.
- *
- * Called when the HC is started.
- */
-int wusbhc_sec_start(struct wusbhc *wusbhc)
-{
-       const size_t key_size = sizeof(wusbhc->gtk.data);
-       int result;
-
-       wusbhc_generate_gtk(wusbhc);
-
-       result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
-                               &wusbhc->gtk.descr.bKeyData, key_size);
-       if (result < 0)
-               dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n",
-                       result);
-
-       return result;
-}
-
-/**
- * wusbhc_sec_stop - stop the security management process
- * @wusbhc: the WUSB host controller
- *
- * Wait for any pending GTK rekeys to stop.
- */
-void wusbhc_sec_stop(struct wusbhc *wusbhc)
-{
-       cancel_work_sync(&wusbhc->gtk_rekey_work);
-}
-
-
-/** @returns encryption type name */
-const char *wusb_et_name(u8 x)
-{
-       switch (x) {
-       case USB_ENC_TYPE_UNSECURE:     return "unsecure";
-       case USB_ENC_TYPE_WIRED:        return "wired";
-       case USB_ENC_TYPE_CCM_1:        return "CCM-1";
-       case USB_ENC_TYPE_RSA_1:        return "RSA-1";
-       default:                        return "unknown";
-       }
-}
-EXPORT_SYMBOL_GPL(wusb_et_name);
-
-/*
- * Set the device encryption method
- *
- * We tell the device which encryption method to use; we do this when
- * setting up the device's security.
- */
-static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value)
-{
-       int result;
-       struct device *dev = &usb_dev->dev;
-       struct wusb_dev *wusb_dev = usb_dev->wusb_dev;
-
-       if (value) {
-               value = wusb_dev->ccm1_etd.bEncryptionValue;
-       } else {
-               /* FIXME: should be wusb_dev->etd[UNSECURE].bEncryptionValue */
-               value = 0;
-       }
-       /* Set device's */
-       result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
-                       USB_REQ_SET_ENCRYPTION,
-                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-                       value, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0)
-               dev_err(dev, "Can't set device's WUSB encryption to "
-                       "%s (value %d): %d\n",
-                       wusb_et_name(wusb_dev->ccm1_etd.bEncryptionType),
-                       wusb_dev->ccm1_etd.bEncryptionValue,  result);
-       return result;
-}
-
-/*
- * Set the GTK to be used by a device.
- *
- * The device must be authenticated.
- */
-static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       struct usb_device *usb_dev = wusb_dev->usb_dev;
-       u8 key_index = wusb_key_index(wusbhc->gtk_index,
-               WUSB_KEY_INDEX_TYPE_GTK, WUSB_KEY_INDEX_ORIGINATOR_HOST);
-
-       return usb_control_msg(
-               usb_dev, usb_sndctrlpipe(usb_dev, 0),
-               USB_REQ_SET_DESCRIPTOR,
-               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-               USB_DT_KEY << 8 | key_index, 0,
-               &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength,
-               USB_CTRL_SET_TIMEOUT);
-}
-
-
-/* FIXME: prototype for adding security */
-int wusb_dev_sec_add(struct wusbhc *wusbhc,
-                    struct usb_device *usb_dev, struct wusb_dev *wusb_dev)
-{
-       int result, bytes, secd_size;
-       struct device *dev = &usb_dev->dev;
-       struct usb_security_descriptor *secd, *new_secd;
-       const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
-       const void *itr, *top;
-       char buf[64];
-
-       secd = kmalloc(sizeof(*secd), GFP_KERNEL);
-       if (secd == NULL) {
-               result = -ENOMEM;
-               goto out;
-       }
-
-       result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
-                                   0, secd, sizeof(*secd));
-       if (result < (int)sizeof(*secd)) {
-               dev_err(dev, "Can't read security descriptor or "
-                       "not enough data: %d\n", result);
-               goto out;
-       }
-       secd_size = le16_to_cpu(secd->wTotalLength);
-       new_secd = krealloc(secd, secd_size, GFP_KERNEL);
-       if (new_secd == NULL) {
-               dev_err(dev,
-                       "Can't allocate space for security descriptors\n");
-               result = -ENOMEM;
-               goto out;
-       }
-       secd = new_secd;
-       result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
-                                   0, secd, secd_size);
-       if (result < secd_size) {
-               dev_err(dev, "Can't read security descriptor or "
-                       "not enough data: %d\n", result);
-               goto out;
-       }
-       bytes = 0;
-       itr = &secd[1];
-       top = (void *)secd + result;
-       while (itr < top) {
-               etd = itr;
-               if (top - itr < sizeof(*etd)) {
-                       dev_err(dev, "BUG: bad device security descriptor; "
-                               "not enough data (%zu vs %zu bytes left)\n",
-                               top - itr, sizeof(*etd));
-                       break;
-               }
-               if (etd->bLength < sizeof(*etd)) {
-                       dev_err(dev, "BUG: bad device encryption descriptor; "
-                               "descriptor is too short "
-                               "(%u vs %zu needed)\n",
-                               etd->bLength, sizeof(*etd));
-                       break;
-               }
-               itr += etd->bLength;
-               bytes += snprintf(buf + bytes, sizeof(buf) - bytes,
-                                 "%s (0x%02x/%02x) ",
-                                 wusb_et_name(etd->bEncryptionType),
-                                 etd->bEncryptionValue, etd->bAuthKeyIndex);
-               if (etd->bEncryptionType == USB_ENC_TYPE_CCM_1)
-                       ccm1_etd = etd;
-       }
-       /* This code only supports CCM1 as of now. */
-       /* FIXME: user has to choose which sec mode to use?
-        * In theory we want CCM */
-       if (ccm1_etd == NULL) {
-               dev_err(dev, "WUSB device doesn't support CCM1 encryption, "
-                       "can't use!\n");
-               result = -EINVAL;
-               goto out;
-       }
-       wusb_dev->ccm1_etd = *ccm1_etd;
-       dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n",
-               buf, wusb_et_name(ccm1_etd->bEncryptionType),
-               ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex);
-       result = 0;
-out:
-       kfree(secd);
-       return result;
-}
-
-void wusb_dev_sec_rm(struct wusb_dev *wusb_dev)
-{
-       /* Nothing so far */
-}
-
-/**
- * Update the address of an unauthenticated WUSB device
- *
- * Once we have successfully authenticated, we take it to addr0 state
- * and then to a normal address.
- *
- * Before the device's address (as known by it) was usb_dev->devnum |
- * 0x80 (unauthenticated address). With this we update it to usb_dev->devnum.
- */
-int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
-{
-       int result = -ENOMEM;
-       struct usb_device *usb_dev = wusb_dev->usb_dev;
-       struct device *dev = &usb_dev->dev;
-       u8 new_address = wusb_dev->addr & 0x7F;
-
-       /* Set address 0 */
-       result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
-                       USB_REQ_SET_ADDRESS,
-                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-                        0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "auth failed: can't set address 0: %d\n",
-                       result);
-               goto error_addr0;
-       }
-       result = wusb_set_dev_addr(wusbhc, wusb_dev, 0);
-       if (result < 0)
-               goto error_addr0;
-       usb_set_device_state(usb_dev, USB_STATE_DEFAULT);
-       usb_ep0_reinit(usb_dev);
-
-       /* Set new (authenticated) address. */
-       result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
-                       USB_REQ_SET_ADDRESS,
-                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-                       new_address, 0, NULL, 0,
-                       USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "auth failed: can't set address %u: %d\n",
-                       new_address, result);
-               goto error_addr;
-       }
-       result = wusb_set_dev_addr(wusbhc, wusb_dev, new_address);
-       if (result < 0)
-               goto error_addr;
-       usb_set_device_state(usb_dev, USB_STATE_ADDRESS);
-       usb_ep0_reinit(usb_dev);
-       usb_dev->authenticated = 1;
-error_addr:
-error_addr0:
-       return result;
-}
-
-/*
- *
- *
- */
-/* FIXME: split and cleanup */
-int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
-                           struct wusb_ckhdid *ck)
-{
-       int result = -ENOMEM;
-       struct usb_device *usb_dev = wusb_dev->usb_dev;
-       struct device *dev = &usb_dev->dev;
-       u32 tkid;
-       struct usb_handshake *hs;
-       struct aes_ccm_nonce ccm_n;
-       u8 mic[8];
-       struct wusb_keydvt_in keydvt_in;
-       struct wusb_keydvt_out keydvt_out;
-
-       hs = kcalloc(3, sizeof(hs[0]), GFP_KERNEL);
-       if (!hs)
-               goto error_kzalloc;
-
-       /* We need to turn encryption before beginning the 4way
-        * hshake (WUSB1.0[.3.2.2]) */
-       result = wusb_dev_set_encryption(usb_dev, 1);
-       if (result < 0)
-               goto error_dev_set_encryption;
-
-       tkid = wusbhc_next_tkid(wusbhc, wusb_dev);
-
-       hs[0].bMessageNumber = 1;
-       hs[0].bStatus = 0;
-       put_unaligned_le32(tkid, hs[0].tTKID);
-       hs[0].bReserved = 0;
-       memcpy(hs[0].CDID, &wusb_dev->cdid, sizeof(hs[0].CDID));
-       get_random_bytes(&hs[0].nonce, sizeof(hs[0].nonce));
-       memset(hs[0].MIC, 0, sizeof(hs[0].MIC)); /* Per WUSB1.0[T7-22] */
-
-       result = usb_control_msg(
-               usb_dev, usb_sndctrlpipe(usb_dev, 0),
-               USB_REQ_SET_HANDSHAKE,
-               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-               1, 0, &hs[0], sizeof(hs[0]), USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Handshake1: request failed: %d\n", result);
-               goto error_hs1;
-       }
-
-       /* Handshake 2, from the device -- need to verify fields */
-       result = usb_control_msg(
-               usb_dev, usb_rcvctrlpipe(usb_dev, 0),
-               USB_REQ_GET_HANDSHAKE,
-               USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-               2, 0, &hs[1], sizeof(hs[1]), USB_CTRL_GET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Handshake2: request failed: %d\n", result);
-               goto error_hs2;
-       }
-
-       result = -EINVAL;
-       if (hs[1].bMessageNumber != 2) {
-               dev_err(dev, "Handshake2 failed: bad message number %u\n",
-                       hs[1].bMessageNumber);
-               goto error_hs2;
-       }
-       if (hs[1].bStatus != 0) {
-               dev_err(dev, "Handshake2 failed: bad status %u\n",
-                       hs[1].bStatus);
-               goto error_hs2;
-       }
-       if (memcmp(hs[0].tTKID, hs[1].tTKID, sizeof(hs[0].tTKID))) {
-               dev_err(dev, "Handshake2 failed: TKID mismatch "
-                       "(#1 0x%02x%02x%02x vs #2 0x%02x%02x%02x)\n",
-                       hs[0].tTKID[0], hs[0].tTKID[1], hs[0].tTKID[2],
-                       hs[1].tTKID[0], hs[1].tTKID[1], hs[1].tTKID[2]);
-               goto error_hs2;
-       }
-       if (memcmp(hs[0].CDID, hs[1].CDID, sizeof(hs[0].CDID))) {
-               dev_err(dev, "Handshake2 failed: CDID mismatch\n");
-               goto error_hs2;
-       }
-
-       /* Setup the CCM nonce */
-       memset(&ccm_n.sfn, 0, sizeof(ccm_n.sfn)); /* Per WUSB1.0[6.5.2] */
-       put_unaligned_le32(tkid, ccm_n.tkid);
-       ccm_n.src_addr = wusbhc->uwb_rc->uwb_dev.dev_addr;
-       ccm_n.dest_addr.data[0] = wusb_dev->addr;
-       ccm_n.dest_addr.data[1] = 0;
-
-       /* Derive the KCK and PTK from CK, the CCM, H and D nonces */
-       memcpy(keydvt_in.hnonce, hs[0].nonce, sizeof(keydvt_in.hnonce));
-       memcpy(keydvt_in.dnonce, hs[1].nonce, sizeof(keydvt_in.dnonce));
-       result = wusb_key_derive(&keydvt_out, ck->data, &ccm_n, &keydvt_in);
-       if (result < 0) {
-               dev_err(dev, "Handshake2 failed: cannot derive keys: %d\n",
-                       result);
-               goto error_hs2;
-       }
-
-       /* Compute MIC and verify it */
-       result = wusb_oob_mic(mic, keydvt_out.kck, &ccm_n, &hs[1]);
-       if (result < 0) {
-               dev_err(dev, "Handshake2 failed: cannot compute MIC: %d\n",
-                       result);
-               goto error_hs2;
-       }
-
-       if (memcmp(hs[1].MIC, mic, sizeof(hs[1].MIC))) {
-               dev_err(dev, "Handshake2 failed: MIC mismatch\n");
-               goto error_hs2;
-       }
-
-       /* Send Handshake3 */
-       hs[2].bMessageNumber = 3;
-       hs[2].bStatus = 0;
-       put_unaligned_le32(tkid, hs[2].tTKID);
-       hs[2].bReserved = 0;
-       memcpy(hs[2].CDID, &wusb_dev->cdid, sizeof(hs[2].CDID));
-       memcpy(hs[2].nonce, hs[0].nonce, sizeof(hs[2].nonce));
-       result = wusb_oob_mic(hs[2].MIC, keydvt_out.kck, &ccm_n, &hs[2]);
-       if (result < 0) {
-               dev_err(dev, "Handshake3 failed: cannot compute MIC: %d\n",
-                       result);
-               goto error_hs2;
-       }
-
-       result = usb_control_msg(
-               usb_dev, usb_sndctrlpipe(usb_dev, 0),
-               USB_REQ_SET_HANDSHAKE,
-               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-               3, 0, &hs[2], sizeof(hs[2]), USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "Handshake3: request failed: %d\n", result);
-               goto error_hs3;
-       }
-
-       result = wusbhc->set_ptk(wusbhc, wusb_dev->port_idx, tkid,
-                                keydvt_out.ptk, sizeof(keydvt_out.ptk));
-       if (result < 0)
-               goto error_wusbhc_set_ptk;
-
-       result = wusb_dev_set_gtk(wusbhc, wusb_dev);
-       if (result < 0) {
-               dev_err(dev, "Set GTK for device: request failed: %d\n",
-                       result);
-               goto error_wusbhc_set_gtk;
-       }
-
-       /* Update the device's address from unauth to auth */
-       if (usb_dev->authenticated == 0) {
-               result = wusb_dev_update_address(wusbhc, wusb_dev);
-               if (result < 0)
-                       goto error_dev_update_address;
-       }
-       result = 0;
-       dev_info(dev, "device authenticated\n");
-
-error_dev_update_address:
-error_wusbhc_set_gtk:
-error_wusbhc_set_ptk:
-error_hs3:
-error_hs2:
-error_hs1:
-       memset(hs, 0, 3*sizeof(hs[0]));
-       memzero_explicit(&keydvt_out, sizeof(keydvt_out));
-       memzero_explicit(&keydvt_in, sizeof(keydvt_in));
-       memzero_explicit(&ccm_n, sizeof(ccm_n));
-       memzero_explicit(mic, sizeof(mic));
-       if (result < 0)
-               wusb_dev_set_encryption(usb_dev, 0);
-error_dev_set_encryption:
-       kfree(hs);
-error_kzalloc:
-       return result;
-}
-
-/*
- * Once all connected and authenticated devices have received the new
- * GTK, switch the host to using it.
- */
-static void wusbhc_gtk_rekey_work(struct work_struct *work)
-{
-       struct wusbhc *wusbhc = container_of(work,
-                                       struct wusbhc, gtk_rekey_work);
-       size_t key_size = sizeof(wusbhc->gtk.data);
-       int port_idx;
-       struct wusb_dev *wusb_dev, *wusb_dev_next;
-       LIST_HEAD(rekey_list);
-
-       mutex_lock(&wusbhc->mutex);
-       /* generate the new key */
-       wusbhc_generate_gtk(wusbhc);
-       /* roll the gtk index. */
-       wusbhc->gtk_index = (wusbhc->gtk_index + 1) % (WUSB_KEY_INDEX_MAX + 1);
-       /*
-        * Save all connected devices on a list while holding wusbhc->mutex and
-        * take a reference to each one.  Then submit the set key request to
-        * them after releasing the lock in order to avoid a deadlock.
-        */
-       for (port_idx = 0; port_idx < wusbhc->ports_max; port_idx++) {
-               wusb_dev = wusbhc->port[port_idx].wusb_dev;
-               if (!wusb_dev || !wusb_dev->usb_dev
-                       || !wusb_dev->usb_dev->authenticated)
-                       continue;
-
-               wusb_dev_get(wusb_dev);
-               list_add_tail(&wusb_dev->rekey_node, &rekey_list);
-       }
-       mutex_unlock(&wusbhc->mutex);
-
-       /* Submit the rekey requests without holding wusbhc->mutex. */
-       list_for_each_entry_safe(wusb_dev, wusb_dev_next, &rekey_list,
-               rekey_node) {
-               list_del_init(&wusb_dev->rekey_node);
-               dev_dbg(&wusb_dev->usb_dev->dev,
-                       "%s: rekey device at port %d\n",
-                       __func__, wusb_dev->port_idx);
-
-               if (wusb_dev_set_gtk(wusbhc, wusb_dev) < 0) {
-                       dev_err(&wusb_dev->usb_dev->dev,
-                               "%s: rekey device at port %d failed\n",
-                               __func__, wusb_dev->port_idx);
-               }
-               wusb_dev_put(wusb_dev);
-       }
-
-       /* Switch the host controller to use the new GTK. */
-       mutex_lock(&wusbhc->mutex);
-       wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid,
-               &wusbhc->gtk.descr.bKeyData, key_size);
-       mutex_unlock(&wusbhc->mutex);
-}
-
-/**
- * wusbhc_gtk_rekey - generate and distribute a new GTK
- * @wusbhc: the WUSB host controller
- *
- * Generate a new GTK and distribute it to all connected and
- * authenticated devices.  When all devices have the new GTK, the host
- * starts using it.
- *
- * This must be called after every device disconnect (see [WUSB]
- * section 6.2.11.2).
- */
-void wusbhc_gtk_rekey(struct wusbhc *wusbhc)
-{
-       /*
-        * We need to submit a URB to the downstream WUSB devices in order to
-        * change the group key.  This can't be done while holding the
-        * wusbhc->mutex since that is also taken in the urb_enqueue routine
-        * and will cause a deadlock.  Instead, queue a work item to do
-        * it when the lock is not held
-        */
-       queue_work(wusbhc->wq_security, &wusbhc->gtk_rekey_work);
-}
diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c
deleted file mode 100644 (file)
index 6827075..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wire Adapter Host Controller Driver
- * Common items to HWA and DWA based HCDs
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- */
-#include <linux/slab.h>
-#include <linux/module.h>
-#include "wusbhc.h"
-#include "wa-hc.h"
-
-/**
- * Assumes
- *
- * wa->usb_dev and wa->usb_iface initialized and refcounted,
- * wa->wa_descr initialized.
- */
-int wa_create(struct wahc *wa, struct usb_interface *iface,
-       kernel_ulong_t quirks)
-{
-       int result;
-       struct device *dev = &iface->dev;
-
-       if (iface->cur_altsetting->desc.bNumEndpoints < 3)
-               return -ENODEV;
-
-       result = wa_rpipes_create(wa);
-       if (result < 0)
-               goto error_rpipes_create;
-       wa->quirks = quirks;
-       /* Fill up Data Transfer EP pointers */
-       wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc;
-       wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
-       wa->dti_buf_size = usb_endpoint_maxp(wa->dti_epd);
-       wa->dti_buf = kmalloc(wa->dti_buf_size, GFP_KERNEL);
-       if (wa->dti_buf == NULL) {
-               result = -ENOMEM;
-               goto error_dti_buf_alloc;
-       }
-       result = wa_nep_create(wa, iface);
-       if (result < 0) {
-               dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n",
-                       result);
-               goto error_nep_create;
-       }
-       return 0;
-
-error_nep_create:
-       kfree(wa->dti_buf);
-error_dti_buf_alloc:
-       wa_rpipes_destroy(wa);
-error_rpipes_create:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wa_create);
-
-
-void __wa_destroy(struct wahc *wa)
-{
-       if (wa->dti_urb) {
-               usb_kill_urb(wa->dti_urb);
-               usb_put_urb(wa->dti_urb);
-       }
-       kfree(wa->dti_buf);
-       wa_nep_destroy(wa);
-       wa_rpipes_destroy(wa);
-}
-EXPORT_SYMBOL_GPL(__wa_destroy);
-
-/**
- * wa_reset_all - reset the WA device
- * @wa: the WA to be reset
- *
- * For HWAs the radio controller and all other PALs are also reset.
- */
-void wa_reset_all(struct wahc *wa)
-{
-       /* FIXME: assuming HWA. */
-       wusbhc_reset_all(wa->wusb);
-}
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Wireless USB Wire Adapter core");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h
deleted file mode 100644 (file)
index ec90fff..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * HWA Host Controller Driver
- * Wire Adapter Control/Data Streaming Iface (WUSB1.0[8])
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This driver implements a USB Host Controller (struct usb_hcd) for a
- * Wireless USB Host Controller based on the Wireless USB 1.0
- * Host-Wire-Adapter specification (in layman terms, a USB-dongle that
- * implements a Wireless USB host).
- *
- * Check out the Design-overview.txt file in the source documentation
- * for other details on the implementation.
- *
- * Main blocks:
- *
- *  driver     glue with the driver API, workqueue daemon
- *
- *  lc         RC instance life cycle management (create, destroy...)
- *
- *  hcd        glue with the USB API Host Controller Interface API.
- *
- *  nep        Notification EndPoint management: collect notifications
- *             and queue them with the workqueue daemon.
- *
- *             Handle notifications as coming from the NEP. Sends them
- *             off others to their respective modules (eg: connect,
- *             disconnect and reset go to devconnect).
- *
- *  rpipe      Remote Pipe management; rpipe is what we use to write
- *             to an endpoint on a WUSB device that is connected to a
- *             HWA RC.
- *
- *  xfer       Transfer management -- this is all the code that gets a
- *             buffer and pushes it to a device (or viceversa). *
- *
- * Some day a lot of this code will be shared between this driver and
- * the drivers for DWA (xfer, rpipe).
- *
- * All starts at driver.c:hwahc_probe(), when one of this guys is
- * connected. hwahc_disconnect() stops it.
- *
- * During operation, the main driver is devices connecting or
- * disconnecting. They cause the HWA RC to send notifications into
- * nep.c:hwahc_nep_cb() that will dispatch them to
- * notif.c:wa_notif_dispatch(). From there they will fan to cause
- * device connects, disconnects, etc.
- *
- * Note much of the activity is difficult to follow. For example a
- * device connect goes to devconnect, which will cause the "fake" root
- * hub port to show a connect and stop there. Then hub_wq will notice
- * and call into the rh.c:hwahc_rc_port_reset() code to authenticate
- * the device (and this might require user intervention) and enable
- * the port.
- *
- * We also have a timer workqueue going from devconnect.c that
- * schedules in hwahc_devconnect_create().
- *
- * The rest of the traffic is in the usual entry points of a USB HCD,
- * which are hooked up in driver.c:hwahc_rc_driver, and defined in
- * hcd.c.
- */
-
-#ifndef __HWAHC_INTERNAL_H__
-#define __HWAHC_INTERNAL_H__
-
-#include <linux/completion.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-#include <linux/spinlock.h>
-#include <linux/uwb.h>
-#include <linux/usb/wusb.h>
-#include <linux/usb/wusb-wa.h>
-
-struct wusbhc;
-struct wahc;
-extern void wa_urb_enqueue_run(struct work_struct *ws);
-extern void wa_process_errored_transfers_run(struct work_struct *ws);
-
-/**
- * RPipe instance
- *
- * @descr's fields are kept in LE, as we need to send it back and
- * forth.
- *
- * @wa is referenced when set
- *
- * @segs_available is the number of requests segments that still can
- *                 be submitted to the controller without overloading
- *                 it. It is initialized to descr->wRequests when
- *                 aiming.
- *
- * A rpipe supports a max of descr->wRequests at the same time; before
- * submitting seg_lock has to be taken. If segs_avail > 0, then we can
- * submit; if not, we have to queue them.
- */
-struct wa_rpipe {
-       struct kref refcnt;
-       struct usb_rpipe_descriptor descr;
-       struct usb_host_endpoint *ep;
-       struct wahc *wa;
-       spinlock_t seg_lock;
-       struct list_head seg_list;
-       struct list_head list_node;
-       atomic_t segs_available;
-       u8 buffer[1];   /* For reads/writes on USB */
-};
-
-
-enum wa_dti_state {
-       WA_DTI_TRANSFER_RESULT_PENDING,
-       WA_DTI_ISOC_PACKET_STATUS_PENDING,
-       WA_DTI_BUF_IN_DATA_PENDING
-};
-
-enum wa_quirks {
-       /*
-        * The Alereon HWA expects the data frames in isochronous transfer
-        * requests to be concatenated and not sent as separate packets.
-        */
-       WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC      = 0x01,
-       /*
-        * The Alereon HWA can be instructed to not send transfer notifications
-        * as an optimization.
-        */
-       WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS       = 0x02,
-};
-
-enum wa_vendor_specific_requests {
-       WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS = 0x4C,
-       WA_REQ_ALEREON_FEATURE_SET = 0x01,
-       WA_REQ_ALEREON_FEATURE_CLEAR = 0x00,
-};
-
-#define WA_MAX_BUF_IN_URBS     4
-/**
- * Instance of a HWA Host Controller
- *
- * Except where a more specific lock/mutex applies or atomic, all
- * fields protected by @mutex.
- *
- * @wa_descr  Can be accessed without locking because it is in
- *            the same area where the device descriptors were
- *            read, so it is guaranteed to exist unmodified while
- *            the device exists.
- *
- *            Endianess has been converted to CPU's.
- *
- * @nep_* can be accessed without locking as its processing is
- *        serialized; we submit a NEP URB and it comes to
- *        hwahc_nep_cb(), which won't issue another URB until it is
- *        done processing it.
- *
- * @xfer_list:
- *
- *   List of active transfers to verify existence from a xfer id
- *   gotten from the xfer result message. Can't use urb->list because
- *   it goes by endpoint, and we don't know the endpoint at the time
- *   when we get the xfer result message. We can't really rely on the
- *   pointer (will have to change for 64 bits) as the xfer id is 32 bits.
- *
- * @xfer_delayed_list:   List of transfers that need to be started
- *                       (with a workqueue, because they were
- *                       submitted from an atomic context).
- *
- * FIXME: this needs to be layered up: a wusbhc layer (for sharing
- *        commonalities with WHCI), a wa layer (for sharing
- *        commonalities with DWA-RC).
- */
-struct wahc {
-       struct usb_device *usb_dev;
-       struct usb_interface *usb_iface;
-
-       /* HC to deliver notifications */
-       union {
-               struct wusbhc *wusb;
-               struct dwahc *dwa;
-       };
-
-       const struct usb_endpoint_descriptor *dto_epd, *dti_epd;
-       const struct usb_wa_descriptor *wa_descr;
-
-       struct urb *nep_urb;            /* Notification EndPoint [lockless] */
-       struct edc nep_edc;
-       void *nep_buffer;
-       size_t nep_buffer_size;
-
-       atomic_t notifs_queued;
-
-       u16 rpipes;
-       unsigned long *rpipe_bm;        /* rpipe usage bitmap */
-       struct list_head rpipe_delayed_list;    /* delayed RPIPES. */
-       spinlock_t rpipe_lock;  /* protect rpipe_bm and delayed list */
-       struct mutex rpipe_mutex;       /* assigning resources to endpoints */
-
-       /*
-        * dti_state is used to track the state of the dti_urb. When dti_state
-        * is WA_DTI_ISOC_PACKET_STATUS_PENDING, dti_isoc_xfer_in_progress and
-        * dti_isoc_xfer_seg identify which xfer the incoming isoc packet
-        * status refers to.
-        */
-       enum wa_dti_state dti_state;
-       u32 dti_isoc_xfer_in_progress;
-       u8  dti_isoc_xfer_seg;
-       struct urb *dti_urb;            /* URB for reading xfer results */
-                                       /* URBs for reading data in */
-       struct urb buf_in_urbs[WA_MAX_BUF_IN_URBS];
-       int active_buf_in_urbs;         /* number of buf_in_urbs active. */
-       struct edc dti_edc;             /* DTI error density counter */
-       void *dti_buf;
-       size_t dti_buf_size;
-
-       unsigned long dto_in_use;       /* protect dto endoint serialization */
-
-       s32 status;                     /* For reading status */
-
-       struct list_head xfer_list;
-       struct list_head xfer_delayed_list;
-       struct list_head xfer_errored_list;
-       /*
-        * lock for the above xfer lists.  Can be taken while a xfer->lock is
-        * held but not in the reverse order.
-        */
-       spinlock_t xfer_list_lock;
-       struct work_struct xfer_enqueue_work;
-       struct work_struct xfer_error_work;
-       atomic_t xfer_id_count;
-
-       kernel_ulong_t  quirks;
-};
-
-
-extern int wa_create(struct wahc *wa, struct usb_interface *iface,
-       kernel_ulong_t);
-extern void __wa_destroy(struct wahc *wa);
-extern int wa_dti_start(struct wahc *wa);
-void wa_reset_all(struct wahc *wa);
-
-
-/* Miscellaneous constants */
-enum {
-       /** Max number of EPROTO errors we tolerate on the NEP in a
-        * period of time */
-       HWAHC_EPROTO_MAX = 16,
-       /** Period of time for EPROTO errors (in jiffies) */
-       HWAHC_EPROTO_PERIOD = 4 * HZ,
-};
-
-
-/* Notification endpoint handling */
-extern int wa_nep_create(struct wahc *, struct usb_interface *);
-extern void wa_nep_destroy(struct wahc *);
-
-static inline int wa_nep_arm(struct wahc *wa, gfp_t gfp_mask)
-{
-       struct urb *urb = wa->nep_urb;
-       urb->transfer_buffer = wa->nep_buffer;
-       urb->transfer_buffer_length = wa->nep_buffer_size;
-       return usb_submit_urb(urb, gfp_mask);
-}
-
-static inline void wa_nep_disarm(struct wahc *wa)
-{
-       usb_kill_urb(wa->nep_urb);
-}
-
-
-/* RPipes */
-static inline void wa_rpipe_init(struct wahc *wa)
-{
-       INIT_LIST_HEAD(&wa->rpipe_delayed_list);
-       spin_lock_init(&wa->rpipe_lock);
-       mutex_init(&wa->rpipe_mutex);
-}
-
-static inline void wa_init(struct wahc *wa)
-{
-       int index;
-
-       edc_init(&wa->nep_edc);
-       atomic_set(&wa->notifs_queued, 0);
-       wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
-       wa_rpipe_init(wa);
-       edc_init(&wa->dti_edc);
-       INIT_LIST_HEAD(&wa->xfer_list);
-       INIT_LIST_HEAD(&wa->xfer_delayed_list);
-       INIT_LIST_HEAD(&wa->xfer_errored_list);
-       spin_lock_init(&wa->xfer_list_lock);
-       INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run);
-       INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run);
-       wa->dto_in_use = 0;
-       atomic_set(&wa->xfer_id_count, 1);
-       /* init the buf in URBs */
-       for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index)
-               usb_init_urb(&(wa->buf_in_urbs[index]));
-       wa->active_buf_in_urbs = 0;
-}
-
-/**
- * Destroy a pipe (when refcount drops to zero)
- *
- * Assumes it has been moved to the "QUIESCING" state.
- */
-struct wa_xfer;
-extern void rpipe_destroy(struct kref *_rpipe);
-static inline
-void __rpipe_get(struct wa_rpipe *rpipe)
-{
-       kref_get(&rpipe->refcnt);
-}
-extern int rpipe_get_by_ep(struct wahc *, struct usb_host_endpoint *,
-                          struct urb *, gfp_t);
-static inline void rpipe_put(struct wa_rpipe *rpipe)
-{
-       kref_put(&rpipe->refcnt, rpipe_destroy);
-
-}
-extern void rpipe_ep_disable(struct wahc *, struct usb_host_endpoint *);
-extern void rpipe_clear_feature_stalled(struct wahc *,
-                       struct usb_host_endpoint *);
-extern int wa_rpipes_create(struct wahc *);
-extern void wa_rpipes_destroy(struct wahc *);
-static inline void rpipe_avail_dec(struct wa_rpipe *rpipe)
-{
-       atomic_dec(&rpipe->segs_available);
-}
-
-/**
- * Returns true if the rpipe is ready to submit more segments.
- */
-static inline int rpipe_avail_inc(struct wa_rpipe *rpipe)
-{
-       return atomic_inc_return(&rpipe->segs_available) > 0
-               && !list_empty(&rpipe->seg_list);
-}
-
-
-/* Transferring data */
-extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *,
-                         struct urb *, gfp_t);
-extern int wa_urb_dequeue(struct wahc *, struct urb *, int);
-extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *);
-
-
-/* Misc
- *
- * FIXME: Refcounting for the actual @hwahc object is not correct; I
- *        mean, this should be refcounting on the HCD underneath, but
- *        it is not. In any case, the semantics for HCD refcounting
- *        are *weird*...on refcount reaching zero it just frees
- *        it...no RC specific function is called...unless I miss
- *        something.
- *
- * FIXME: has to go away in favour of a 'struct' hcd based solution
- */
-static inline struct wahc *wa_get(struct wahc *wa)
-{
-       usb_get_intf(wa->usb_iface);
-       return wa;
-}
-
-static inline void wa_put(struct wahc *wa)
-{
-       usb_put_intf(wa->usb_iface);
-}
-
-
-static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature)
-{
-       return usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       op ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       feature,
-                       wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-                       NULL, 0, USB_CTRL_SET_TIMEOUT);
-}
-
-
-static inline int __wa_set_feature(struct wahc *wa, u16 feature)
-{
-       return  __wa_feature(wa, 1, feature);
-}
-
-
-static inline int __wa_clear_feature(struct wahc *wa, u16 feature)
-{
-       return __wa_feature(wa, 0, feature);
-}
-
-
-/**
- * Return the status of a Wire Adapter
- *
- * @wa:                Wire Adapter instance
- * @returns     < 0 errno code on error, or status bitmap as described
- *              in WUSB1.0[8.3.1.6].
- *
- * NOTE: need malloc, some arches don't take USB from the stack
- */
-static inline
-s32 __wa_get_status(struct wahc *wa)
-{
-       s32 result;
-       result = usb_control_msg(
-               wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
-               USB_REQ_GET_STATUS,
-               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-               &wa->status, sizeof(wa->status), USB_CTRL_GET_TIMEOUT);
-       if (result >= 0)
-               result = wa->status;
-       return result;
-}
-
-
-/**
- * Waits until the Wire Adapter's status matches @mask/@value
- *
- * @wa:                Wire Adapter instance.
- * @returns     < 0 errno code on error, otherwise status.
- *
- * Loop until the WAs status matches the mask and value (status & mask
- * == value). Timeout if it doesn't happen.
- *
- * FIXME: is there an official specification on how long status
- *        changes can take?
- */
-static inline s32 __wa_wait_status(struct wahc *wa, u32 mask, u32 value)
-{
-       s32 result;
-       unsigned loops = 10;
-       do {
-               msleep(50);
-               result = __wa_get_status(wa);
-               if ((result & mask) == value)
-                       break;
-               if (loops-- == 0) {
-                       result = -ETIMEDOUT;
-                       break;
-               }
-       } while (result >= 0);
-       return result;
-}
-
-
-/** Command @hwahc to stop, @returns 0 if ok, < 0 errno code on error */
-static inline int __wa_stop(struct wahc *wa)
-{
-       int result;
-       struct device *dev = &wa->usb_iface->dev;
-
-       result = __wa_clear_feature(wa, WA_ENABLE);
-       if (result < 0 && result != -ENODEV) {
-               dev_err(dev, "error commanding HC to stop: %d\n", result);
-               goto out;
-       }
-       result = __wa_wait_status(wa, WA_ENABLE, 0);
-       if (result < 0 && result != -ENODEV)
-               dev_err(dev, "error waiting for HC to stop: %d\n", result);
-out:
-       return 0;
-}
-
-
-#endif /* #ifndef __HWAHC_INTERNAL_H__ */
diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c
deleted file mode 100644 (file)
index 5f0656d..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB Wire Adapter: Control/Data Streaming Interface (WUSB[8])
- * Notification EndPoint support
- *
- * Copyright (C) 2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This part takes care of getting the notification from the hw
- * only and dispatching through wusbwad into
- * wa_notif_dispatch. Handling is done there.
- *
- * WA notifications are limited in size; most of them are three or
- * four bytes long, and the longest is the HWA Device Notification,
- * which would not exceed 38 bytes (DNs are limited in payload to 32
- * bytes plus 3 bytes header (WUSB1.0[7.6p2]), plus 3 bytes HWA
- * header (WUSB1.0[8.5.4.2]).
- *
- * It is not clear if more than one Device Notification can be packed
- * in a HWA Notification, I assume no because of the wording in
- * WUSB1.0[8.5.4.2]. In any case, the bigger any notification could
- * get is 256 bytes (as the bLength field is a byte).
- *
- * So what we do is we have this buffer and read into it; when a
- * notification arrives we schedule work to a specific, single thread
- * workqueue (so notifications are serialized) and copy the
- * notification data. After scheduling the work, we rearm the read from
- * the notification endpoint.
- *
- * Entry points here are:
- *
- * wa_nep_[create|destroy]()   To initialize/release this subsystem
- *
- * wa_nep_cb()                 Callback for the notification
- *                                endpoint; when data is ready, this
- *                                does the dispatching.
- */
-#include <linux/workqueue.h>
-#include <linux/ctype.h>
-#include <linux/slab.h>
-
-#include "wa-hc.h"
-#include "wusbhc.h"
-
-/* Structure for queueing notifications to the workqueue */
-struct wa_notif_work {
-       struct work_struct work;
-       struct wahc *wa;
-       size_t size;
-       u8 data[];
-};
-
-/*
- * Process incoming notifications from the WA's Notification EndPoint
- * [the wuswad daemon, basically]
- *
- * @_nw:       Pointer to a descriptor which has the pointer to the
- *             @wa, the size of the buffer and the work queue
- *             structure (so we can free all when done).
- * @returns     0 if ok, < 0 errno code on error.
- *
- * All notifications follow the same format; they need to start with a
- * 'struct wa_notif_hdr' header, so it is easy to parse through
- * them. We just break the buffer in individual notifications (the
- * standard doesn't say if it can be done or is forbidden, so we are
- * cautious) and dispatch each.
- *
- * So the handling layers are is:
- *
- *   WA specific notification (from NEP)
- *      Device Notification Received -> wa_handle_notif_dn()
- *        WUSB Device notification generic handling
- *      BPST Adjustment -> wa_handle_notif_bpst_adj()
- *      ... -> ...
- *
- * @wa has to be referenced
- */
-static void wa_notif_dispatch(struct work_struct *ws)
-{
-       void *itr;
-       u8 missing = 0;
-       struct wa_notif_work *nw = container_of(ws, struct wa_notif_work,
-                                               work);
-       struct wahc *wa = nw->wa;
-       struct wa_notif_hdr *notif_hdr;
-       size_t size;
-
-       struct device *dev = &wa->usb_iface->dev;
-
-#if 0
-       /* FIXME: need to check for this??? */
-       if (usb_hcd->state == HC_STATE_QUIESCING)       /* Going down? */
-               goto out;                               /* screw it */
-#endif
-       atomic_dec(&wa->notifs_queued);         /* Throttling ctl */
-       size = nw->size;
-       itr = nw->data;
-
-       while (size) {
-               if (size < sizeof(*notif_hdr)) {
-                       missing = sizeof(*notif_hdr) - size;
-                       goto exhausted_buffer;
-               }
-               notif_hdr = itr;
-               if (size < notif_hdr->bLength)
-                       goto exhausted_buffer;
-               itr += notif_hdr->bLength;
-               size -= notif_hdr->bLength;
-               /* Dispatch the notification [don't use itr or size!] */
-               switch (notif_hdr->bNotifyType) {
-               case HWA_NOTIF_DN: {
-                       struct hwa_notif_dn *hwa_dn;
-                       hwa_dn = container_of(notif_hdr, struct hwa_notif_dn,
-                                             hdr);
-                       wusbhc_handle_dn(wa->wusb, hwa_dn->bSourceDeviceAddr,
-                                        hwa_dn->dndata,
-                                        notif_hdr->bLength - sizeof(*hwa_dn));
-                       break;
-               }
-               case WA_NOTIF_TRANSFER:
-                       wa_handle_notif_xfer(wa, notif_hdr);
-                       break;
-               case HWA_NOTIF_BPST_ADJ:
-                       break; /* no action needed for BPST ADJ. */
-               case DWA_NOTIF_RWAKE:
-               case DWA_NOTIF_PORTSTATUS:
-                       /* FIXME: unimplemented WA NOTIFs */
-                       /* fallthru */
-               default:
-                       dev_err(dev, "HWA: unknown notification 0x%x, "
-                               "%zu bytes; discarding\n",
-                               notif_hdr->bNotifyType,
-                               (size_t)notif_hdr->bLength);
-                       break;
-               }
-       }
-out:
-       wa_put(wa);
-       kfree(nw);
-       return;
-
-       /* THIS SHOULD NOT HAPPEN
-        *
-        * Buffer exahusted with partial data remaining; just warn and
-        * discard the data, as this should not happen.
-        */
-exhausted_buffer:
-       dev_warn(dev, "HWA: device sent short notification, "
-                "%d bytes missing; discarding %d bytes.\n",
-                missing, (int)size);
-       goto out;
-}
-
-/*
- * Deliver incoming WA notifications to the wusbwa workqueue
- *
- * @wa:        Pointer the Wire Adapter Controller Data Streaming
- *              instance (part of an 'struct usb_hcd').
- * @size:       Size of the received buffer
- * @returns     0 if ok, < 0 errno code on error.
- *
- * The input buffer is @wa->nep_buffer, with @size bytes
- * (guaranteed to fit in the allocated space,
- * @wa->nep_buffer_size).
- */
-static int wa_nep_queue(struct wahc *wa, size_t size)
-{
-       int result = 0;
-       struct device *dev = &wa->usb_iface->dev;
-       struct wa_notif_work *nw;
-
-       /* dev_fnstart(dev, "(wa %p, size %zu)\n", wa, size); */
-       BUG_ON(size > wa->nep_buffer_size);
-       if (size == 0)
-               goto out;
-       if (atomic_read(&wa->notifs_queued) > 200) {
-               if (printk_ratelimit())
-                       dev_err(dev, "Too many notifications queued, "
-                               "throttling back\n");
-               goto out;
-       }
-       nw = kzalloc(sizeof(*nw) + size, GFP_ATOMIC);
-       if (nw == NULL) {
-               if (printk_ratelimit())
-                       dev_err(dev, "No memory to queue notification\n");
-               result = -ENOMEM;
-               goto out;
-       }
-       INIT_WORK(&nw->work, wa_notif_dispatch);
-       nw->wa = wa_get(wa);
-       nw->size = size;
-       memcpy(nw->data, wa->nep_buffer, size);
-       atomic_inc(&wa->notifs_queued);         /* Throttling ctl */
-       queue_work(wusbd, &nw->work);
-out:
-       /* dev_fnend(dev, "(wa %p, size %zu) = result\n", wa, size, result); */
-       return result;
-}
-
-/*
- * Callback for the notification event endpoint
- *
- * Check's that everything is fine and then passes the data to be
- * queued to the workqueue.
- */
-static void wa_nep_cb(struct urb *urb)
-{
-       int result;
-       struct wahc *wa = urb->context;
-       struct device *dev = &wa->usb_iface->dev;
-
-       switch (result = urb->status) {
-       case 0:
-               result = wa_nep_queue(wa, urb->actual_length);
-               if (result < 0)
-                       dev_err(dev, "NEP: unable to process notification(s): "
-                               "%d\n", result);
-               break;
-       case -ECONNRESET:       /* Not an error, but a controlled situation; */
-       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
-       case -ESHUTDOWN:
-               dev_dbg(dev, "NEP: going down %d\n", urb->status);
-               goto out;
-       default:        /* On general errors, we retry unless it gets ugly */
-               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)) {
-                       dev_err(dev, "NEP: URB max acceptable errors "
-                               "exceeded, resetting device\n");
-                       wa_reset_all(wa);
-                       goto out;
-               }
-               dev_err(dev, "NEP: URB error %d\n", urb->status);
-       }
-       result = wa_nep_arm(wa, GFP_ATOMIC);
-       if (result < 0) {
-               dev_err(dev, "NEP: cannot submit URB: %d\n", result);
-               wa_reset_all(wa);
-       }
-out:
-       return;
-}
-
-/*
- * Initialize @wa's notification and event's endpoint stuff
- *
- * This includes the allocating the read buffer, the context ID
- * allocation bitmap, the URB and submitting the URB.
- */
-int wa_nep_create(struct wahc *wa, struct usb_interface *iface)
-{
-       int result;
-       struct usb_endpoint_descriptor *epd;
-       struct usb_device *usb_dev = interface_to_usbdev(iface);
-       struct device *dev = &iface->dev;
-
-       edc_init(&wa->nep_edc);
-       epd = &iface->cur_altsetting->endpoint[0].desc;
-       wa->nep_buffer_size = 1024;
-       wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL);
-       if (!wa->nep_buffer)
-               goto error_nep_buffer;
-       wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (wa->nep_urb == NULL)
-               goto error_urb_alloc;
-       usb_fill_int_urb(wa->nep_urb, usb_dev,
-                        usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
-                        wa->nep_buffer, wa->nep_buffer_size,
-                        wa_nep_cb, wa, epd->bInterval);
-       result = wa_nep_arm(wa, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "Cannot submit notification URB: %d\n", result);
-               goto error_nep_arm;
-       }
-       return 0;
-
-error_nep_arm:
-       usb_free_urb(wa->nep_urb);
-error_urb_alloc:
-       kfree(wa->nep_buffer);
-error_nep_buffer:
-       return -ENOMEM;
-}
-
-void wa_nep_destroy(struct wahc *wa)
-{
-       wa_nep_disarm(wa);
-       usb_free_urb(wa->nep_urb);
-       kfree(wa->nep_buffer);
-}
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
deleted file mode 100644 (file)
index a5734cb..0000000
+++ /dev/null
@@ -1,539 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB Wire Adapter
- * rpipe management
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- *
- * RPIPE
- *
- *   Targeted at different downstream endpoints
- *
- *   Descriptor: use to config the remote pipe.
- *
- *   The number of blocks could be dynamic (wBlocks in descriptor is
- *   0)--need to schedule them then.
- *
- * Each bit in wa->rpipe_bm represents if an rpipe is being used or
- * not. Rpipes are represented with a 'struct wa_rpipe' that is
- * attached to the hcpriv member of a 'struct usb_host_endpoint'.
- *
- * When you need to xfer data to an endpoint, you get an rpipe for it
- * with wa_ep_rpipe_get(), which gives you a reference to the rpipe
- * and keeps a single one (the first one) with the endpoint. When you
- * are done transferring, you drop that reference. At the end the
- * rpipe is always allocated and bound to the endpoint. There it might
- * be recycled when not used.
- *
- * Addresses:
- *
- *  We use a 1:1 mapping mechanism between port address (0 based
- *  index, actually) and the address. The USB stack knows about this.
- *
- *  USB Stack port number    4 (1 based)
- *  WUSB code port index     3 (0 based)
- *  USB Address             5 (2 based -- 0 is for default, 1 for root hub)
- *
- *  Now, because we don't use the concept as default address exactly
- *  like the (wired) USB code does, we need to kind of skip it. So we
- *  never take addresses from the urb->pipe, but from the
- *  urb->dev->devnum, to make sure that we always have the right
- *  destination address.
- */
-#include <linux/atomic.h>
-#include <linux/bitmap.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include "wusbhc.h"
-#include "wa-hc.h"
-
-static int __rpipe_get_descr(struct wahc *wa,
-                            struct usb_rpipe_descriptor *descr, u16 index)
-{
-       ssize_t result;
-       struct device *dev = &wa->usb_iface->dev;
-
-       /* Get the RPIPE descriptor -- we cannot use the usb_get_descriptor()
-        * function because the arguments are different.
-        */
-       result = usb_control_msg(
-               wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0),
-               USB_REQ_GET_DESCRIPTOR,
-               USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE,
-               USB_DT_RPIPE<<8, index, descr, sizeof(*descr),
-               USB_CTRL_GET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "rpipe %u: get descriptor failed: %d\n",
-                       index, (int)result);
-               goto error;
-       }
-       if (result < sizeof(*descr)) {
-               dev_err(dev, "rpipe %u: got short descriptor "
-                       "(%zd vs %zd bytes needed)\n",
-                       index, result, sizeof(*descr));
-               result = -EINVAL;
-               goto error;
-       }
-       result = 0;
-
-error:
-       return result;
-}
-
-/*
- *
- * The descriptor is assumed to be properly initialized (ie: you got
- * it through __rpipe_get_descr()).
- */
-static int __rpipe_set_descr(struct wahc *wa,
-                            struct usb_rpipe_descriptor *descr, u16 index)
-{
-       ssize_t result;
-       struct device *dev = &wa->usb_iface->dev;
-
-       /* we cannot use the usb_get_descriptor() function because the
-        * arguments are different.
-        */
-       result = usb_control_msg(
-               wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-               USB_REQ_SET_DESCRIPTOR,
-               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
-               USB_DT_RPIPE<<8, index, descr, sizeof(*descr),
-               USB_CTRL_SET_TIMEOUT);
-       if (result < 0) {
-               dev_err(dev, "rpipe %u: set descriptor failed: %d\n",
-                       index, (int)result);
-               goto error;
-       }
-       if (result < sizeof(*descr)) {
-               dev_err(dev, "rpipe %u: sent short descriptor "
-                       "(%zd vs %zd bytes required)\n",
-                       index, result, sizeof(*descr));
-               result = -EINVAL;
-               goto error;
-       }
-       result = 0;
-
-error:
-       return result;
-
-}
-
-static void rpipe_init(struct wa_rpipe *rpipe)
-{
-       kref_init(&rpipe->refcnt);
-       spin_lock_init(&rpipe->seg_lock);
-       INIT_LIST_HEAD(&rpipe->seg_list);
-       INIT_LIST_HEAD(&rpipe->list_node);
-}
-
-static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&wa->rpipe_lock, flags);
-       rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx);
-       if (rpipe_idx < wa->rpipes)
-               set_bit(rpipe_idx, wa->rpipe_bm);
-       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
-
-       return rpipe_idx;
-}
-
-static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&wa->rpipe_lock, flags);
-       clear_bit(rpipe_idx, wa->rpipe_bm);
-       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
-}
-
-void rpipe_destroy(struct kref *_rpipe)
-{
-       struct wa_rpipe *rpipe = container_of(_rpipe, struct wa_rpipe, refcnt);
-       u8 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
-
-       if (rpipe->ep)
-               rpipe->ep->hcpriv = NULL;
-       rpipe_put_idx(rpipe->wa, index);
-       wa_put(rpipe->wa);
-       kfree(rpipe);
-}
-EXPORT_SYMBOL_GPL(rpipe_destroy);
-
-/*
- * Locate an idle rpipe, create an structure for it and return it
- *
- * @wa   is referenced and unlocked
- * @crs   enum rpipe_attr, required endpoint characteristics
- *
- * The rpipe can be used only sequentially (not in parallel).
- *
- * The rpipe is moved into the "ready" state.
- */
-static int rpipe_get_idle(struct wa_rpipe **prpipe, struct wahc *wa, u8 crs,
-                         gfp_t gfp)
-{
-       int result;
-       unsigned rpipe_idx;
-       struct wa_rpipe *rpipe;
-       struct device *dev = &wa->usb_iface->dev;
-
-       rpipe = kzalloc(sizeof(*rpipe), gfp);
-       if (rpipe == NULL)
-               return -ENOMEM;
-       rpipe_init(rpipe);
-
-       /* Look for an idle pipe */
-       for (rpipe_idx = 0; rpipe_idx < wa->rpipes; rpipe_idx++) {
-               rpipe_idx = rpipe_get_idx(wa, rpipe_idx);
-               if (rpipe_idx >= wa->rpipes)    /* no more pipes :( */
-                       break;
-               result =  __rpipe_get_descr(wa, &rpipe->descr, rpipe_idx);
-               if (result < 0)
-                       dev_err(dev, "Can't get descriptor for rpipe %u: %d\n",
-                               rpipe_idx, result);
-               else if ((rpipe->descr.bmCharacteristics & crs) != 0)
-                       goto found;
-               rpipe_put_idx(wa, rpipe_idx);
-       }
-       *prpipe = NULL;
-       kfree(rpipe);
-       return -ENXIO;
-
-found:
-       set_bit(rpipe_idx, wa->rpipe_bm);
-       rpipe->wa = wa_get(wa);
-       *prpipe = rpipe;
-       return 0;
-}
-
-static int __rpipe_reset(struct wahc *wa, unsigned index)
-{
-       int result;
-       struct device *dev = &wa->usb_iface->dev;
-
-       result = usb_control_msg(
-               wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-               USB_REQ_RPIPE_RESET,
-               USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
-               0, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
-       if (result < 0)
-               dev_err(dev, "rpipe %u: reset failed: %d\n",
-                       index, result);
-       return result;
-}
-
-/*
- * Fake companion descriptor for ep0
- *
- * See WUSB1.0[7.4.4], most of this is zero for bulk/int/ctl
- */
-static struct usb_wireless_ep_comp_descriptor epc0 = {
-       .bLength = sizeof(epc0),
-       .bDescriptorType = USB_DT_WIRELESS_ENDPOINT_COMP,
-       .bMaxBurst = 1,
-       .bMaxSequence = 2,
-};
-
-/*
- * Look for EP companion descriptor
- *
- * Get there, look for Inara in the endpoint's extra descriptors
- */
-static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find(
-               struct device *dev, struct usb_host_endpoint *ep)
-{
-       void *itr;
-       size_t itr_size;
-       struct usb_descriptor_header *hdr;
-       struct usb_wireless_ep_comp_descriptor *epcd;
-
-       if (ep->desc.bEndpointAddress == 0) {
-               epcd = &epc0;
-               goto out;
-       }
-       itr = ep->extra;
-       itr_size = ep->extralen;
-       epcd = NULL;
-       while (itr_size > 0) {
-               if (itr_size < sizeof(*hdr)) {
-                       dev_err(dev, "HW Bug? ep 0x%02x: extra descriptors "
-                               "at offset %zu: only %zu bytes left\n",
-                               ep->desc.bEndpointAddress,
-                               itr - (void *) ep->extra, itr_size);
-                       break;
-               }
-               hdr = itr;
-               if (hdr->bDescriptorType == USB_DT_WIRELESS_ENDPOINT_COMP) {
-                       epcd = itr;
-                       break;
-               }
-               if (hdr->bLength > itr_size) {
-                       dev_err(dev, "HW Bug? ep 0x%02x: extra descriptor "
-                               "at offset %zu (type 0x%02x) "
-                               "length %d but only %zu bytes left\n",
-                               ep->desc.bEndpointAddress,
-                               itr - (void *) ep->extra, hdr->bDescriptorType,
-                               hdr->bLength, itr_size);
-                       break;
-               }
-               itr += hdr->bLength;
-               itr_size -= hdr->bLength;
-       }
-out:
-       return epcd;
-}
-
-/*
- * Aim an rpipe to its device & endpoint destination
- *
- * Make sure we change the address to unauthenticated if the device
- * is WUSB and it is not authenticated.
- */
-static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,
-                    struct usb_host_endpoint *ep, struct urb *urb, gfp_t gfp)
-{
-       int result = -ENOMSG;   /* better code for lack of companion? */
-       struct device *dev = &wa->usb_iface->dev;
-       struct usb_device *usb_dev = urb->dev;
-       struct usb_wireless_ep_comp_descriptor *epcd;
-       u32 ack_window, epcd_max_sequence;
-       u8 unauth;
-
-       epcd = rpipe_epc_find(dev, ep);
-       if (epcd == NULL) {
-               dev_err(dev, "ep 0x%02x: can't find companion descriptor\n",
-                       ep->desc.bEndpointAddress);
-               goto error;
-       }
-       unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0;
-       __rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex));
-       atomic_set(&rpipe->segs_available,
-               le16_to_cpu(rpipe->descr.wRequests));
-       /* FIXME: block allocation system; request with queuing and timeout */
-       /* FIXME: compute so seg_size > ep->maxpktsize */
-       rpipe->descr.wBlocks = cpu_to_le16(16);         /* given */
-       /* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */
-       if (usb_endpoint_xfer_isoc(&ep->desc))
-               rpipe->descr.wMaxPacketSize = epcd->wOverTheAirPacketSize;
-       else
-               rpipe->descr.wMaxPacketSize = ep->desc.wMaxPacketSize;
-
-       rpipe->descr.hwa_bMaxBurst = max(min_t(unsigned int,
-                               epcd->bMaxBurst, 16U), 1U);
-       rpipe->descr.hwa_bDeviceInfoIndex =
-                       wusb_port_no_to_idx(urb->dev->portnum);
-       /* FIXME: use maximum speed as supported or recommended by device */
-       rpipe->descr.bSpeed = usb_pipeendpoint(urb->pipe) == 0 ?
-               UWB_PHY_RATE_53 : UWB_PHY_RATE_200;
-
-       dev_dbg(dev, "addr %u (0x%02x) rpipe #%u ep# %u speed %d\n",
-               urb->dev->devnum, urb->dev->devnum | unauth,
-               le16_to_cpu(rpipe->descr.wRPipeIndex),
-               usb_pipeendpoint(urb->pipe), rpipe->descr.bSpeed);
-
-       rpipe->descr.hwa_reserved = 0;
-
-       rpipe->descr.bEndpointAddress = ep->desc.bEndpointAddress;
-       /* FIXME: bDataSequence */
-       rpipe->descr.bDataSequence = 0;
-
-       /* start with base window of hwa_bMaxBurst bits starting at 0. */
-       ack_window = 0xFFFFFFFF >> (32 - rpipe->descr.hwa_bMaxBurst);
-       rpipe->descr.dwCurrentWindow = cpu_to_le32(ack_window);
-       epcd_max_sequence = max(min_t(unsigned int,
-                       epcd->bMaxSequence, 32U), 2U);
-       rpipe->descr.bMaxDataSequence = epcd_max_sequence - 1;
-       rpipe->descr.bInterval = ep->desc.bInterval;
-       if (usb_endpoint_xfer_isoc(&ep->desc))
-               rpipe->descr.bOverTheAirInterval = epcd->bOverTheAirInterval;
-       else
-               rpipe->descr.bOverTheAirInterval = 0;   /* 0 if not isoc */
-       /* FIXME: xmit power & preamble blah blah */
-       rpipe->descr.bmAttribute = (ep->desc.bmAttributes &
-                                       USB_ENDPOINT_XFERTYPE_MASK);
-       /* rpipe->descr.bmCharacteristics RO */
-       rpipe->descr.bmRetryOptions = (wa->wusb->retry_count & 0xF);
-       /* FIXME: use for assessing link quality? */
-       rpipe->descr.wNumTransactionErrors = 0;
-       result = __rpipe_set_descr(wa, &rpipe->descr,
-                                  le16_to_cpu(rpipe->descr.wRPipeIndex));
-       if (result < 0) {
-               dev_err(dev, "Cannot aim rpipe: %d\n", result);
-               goto error;
-       }
-       result = 0;
-error:
-       return result;
-}
-
-/*
- * Check an aimed rpipe to make sure it points to where we want
- *
- * We use bit 19 of the Linux USB pipe bitmap for unauth vs auth
- * space; when it is like that, we or 0x80 to make an unauth address.
- */
-static int rpipe_check_aim(const struct wa_rpipe *rpipe, const struct wahc *wa,
-                          const struct usb_host_endpoint *ep,
-                          const struct urb *urb, gfp_t gfp)
-{
-       int result = 0;
-       struct device *dev = &wa->usb_iface->dev;
-       u8 portnum = wusb_port_no_to_idx(urb->dev->portnum);
-
-#define AIM_CHECK(rdf, val, text)                                      \
-       do {                                                            \
-               if (rpipe->descr.rdf != (val)) {                        \
-                       dev_err(dev,                                    \
-                               "rpipe aim discrepancy: " #rdf " " text "\n", \
-                               rpipe->descr.rdf, (val));               \
-                       result = -EINVAL;                               \
-                       WARN_ON(1);                                     \
-               }                                                       \
-       } while (0)
-       AIM_CHECK(hwa_bDeviceInfoIndex, portnum, "(%u vs %u)");
-       AIM_CHECK(bSpeed, usb_pipeendpoint(urb->pipe) == 0 ?
-                       UWB_PHY_RATE_53 : UWB_PHY_RATE_200,
-                 "(%u vs %u)");
-       AIM_CHECK(bEndpointAddress, ep->desc.bEndpointAddress, "(%u vs %u)");
-       AIM_CHECK(bInterval, ep->desc.bInterval, "(%u vs %u)");
-       AIM_CHECK(bmAttribute, ep->desc.bmAttributes & 0x03, "(%u vs %u)");
-#undef AIM_CHECK
-       return result;
-}
-
-#ifndef CONFIG_BUG
-#define CONFIG_BUG 0
-#endif
-
-/*
- * Make sure there is an rpipe allocated for an endpoint
- *
- * If already allocated, we just refcount it; if not, we get an
- * idle one, aim it to the right location and take it.
- *
- * Attaches to ep->hcpriv and rpipe->ep to ep.
- */
-int rpipe_get_by_ep(struct wahc *wa, struct usb_host_endpoint *ep,
-                   struct urb *urb, gfp_t gfp)
-{
-       int result = 0;
-       struct device *dev = &wa->usb_iface->dev;
-       struct wa_rpipe *rpipe;
-       u8 eptype;
-
-       mutex_lock(&wa->rpipe_mutex);
-       rpipe = ep->hcpriv;
-       if (rpipe != NULL) {
-               if (CONFIG_BUG == 1) {
-                       result = rpipe_check_aim(rpipe, wa, ep, urb, gfp);
-                       if (result < 0)
-                               goto error;
-               }
-               __rpipe_get(rpipe);
-               dev_dbg(dev, "ep 0x%02x: reusing rpipe %u\n",
-                       ep->desc.bEndpointAddress,
-                       le16_to_cpu(rpipe->descr.wRPipeIndex));
-       } else {
-               /* hmm, assign idle rpipe, aim it */
-               result = -ENOBUFS;
-               eptype = ep->desc.bmAttributes & 0x03;
-               result = rpipe_get_idle(&rpipe, wa, 1 << eptype, gfp);
-               if (result < 0)
-                       goto error;
-               result = rpipe_aim(rpipe, wa, ep, urb, gfp);
-               if (result < 0) {
-                       rpipe_put(rpipe);
-                       goto error;
-               }
-               ep->hcpriv = rpipe;
-               rpipe->ep = ep;
-               __rpipe_get(rpipe);     /* for caching into ep->hcpriv */
-               dev_dbg(dev, "ep 0x%02x: using rpipe %u\n",
-                       ep->desc.bEndpointAddress,
-                       le16_to_cpu(rpipe->descr.wRPipeIndex));
-       }
-error:
-       mutex_unlock(&wa->rpipe_mutex);
-       return result;
-}
-
-/*
- * Allocate the bitmap for each rpipe.
- */
-int wa_rpipes_create(struct wahc *wa)
-{
-       wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes);
-       wa->rpipe_bm = bitmap_zalloc(wa->rpipes, GFP_KERNEL);
-       if (wa->rpipe_bm == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-void wa_rpipes_destroy(struct wahc *wa)
-{
-       struct device *dev = &wa->usb_iface->dev;
-
-       if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) {
-               WARN_ON(1);
-               dev_err(dev, "BUG: pipes not released on exit: %*pb\n",
-                       wa->rpipes, wa->rpipe_bm);
-       }
-       bitmap_free(wa->rpipe_bm);
-}
-
-/*
- * Release resources allocated for an endpoint
- *
- * If there is an associated rpipe to this endpoint, Abort any pending
- * transfers and put it. If the rpipe ends up being destroyed,
- * __rpipe_destroy() will cleanup ep->hcpriv.
- *
- * This is called before calling hcd->stop(), so you don't need to do
- * anything else in there.
- */
-void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep)
-{
-       struct wa_rpipe *rpipe;
-
-       mutex_lock(&wa->rpipe_mutex);
-       rpipe = ep->hcpriv;
-       if (rpipe != NULL) {
-               u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
-
-               usb_control_msg(
-                       wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       USB_REQ_RPIPE_ABORT,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
-                       0, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
-               rpipe_put(rpipe);
-       }
-       mutex_unlock(&wa->rpipe_mutex);
-}
-EXPORT_SYMBOL_GPL(rpipe_ep_disable);
-
-/* Clear the stalled status of an RPIPE. */
-void rpipe_clear_feature_stalled(struct wahc *wa, struct usb_host_endpoint *ep)
-{
-       struct wa_rpipe *rpipe;
-
-       mutex_lock(&wa->rpipe_mutex);
-       rpipe = ep->hcpriv;
-       if (rpipe != NULL) {
-               u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);
-
-               usb_control_msg(
-                       wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),
-                       USB_REQ_CLEAR_FEATURE,
-                       USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,
-                       RPIPE_STALL, index, NULL, 0, USB_CTRL_SET_TIMEOUT);
-       }
-       mutex_unlock(&wa->rpipe_mutex);
-}
-EXPORT_SYMBOL_GPL(rpipe_clear_feature_stalled);
diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c
deleted file mode 100644 (file)
index abf88ce..0000000
+++ /dev/null
@@ -1,2927 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * WUSB Wire Adapter
- * Data transfer and URB enqueing
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * How transfers work: get a buffer, break it up in segments (segment
- * size is a multiple of the maxpacket size). For each segment issue a
- * segment request (struct wa_xfer_*), then send the data buffer if
- * out or nothing if in (all over the DTO endpoint).
- *
- * For each submitted segment request, a notification will come over
- * the NEP endpoint and a transfer result (struct xfer_result) will
- * arrive in the DTI URB. Read it, get the xfer ID, see if there is
- * data coming (inbound transfer), schedule a read and handle it.
- *
- * Sounds simple, it is a pain to implement.
- *
- *
- * ENTRY POINTS
- *
- *   FIXME
- *
- * LIFE CYCLE / STATE DIAGRAM
- *
- *   FIXME
- *
- * THIS CODE IS DISGUSTING
- *
- *   Warned you are; it's my second try and still not happy with it.
- *
- * NOTES:
- *
- *   - No iso
- *
- *   - Supports DMA xfers, control, bulk and maybe interrupt
- *
- *   - Does not recycle unused rpipes
- *
- *     An rpipe is assigned to an endpoint the first time it is used,
- *     and then it's there, assigned, until the endpoint is disabled
- *     (destroyed [{h,d}wahc_op_ep_disable()]. The assignment of the
- *     rpipe to the endpoint is done under the wa->rpipe_sem semaphore
- *     (should be a mutex).
- *
- *     Two methods it could be done:
- *
- *     (a) set up a timer every time an rpipe's use count drops to 1
- *         (which means unused) or when a transfer ends. Reset the
- *         timer when a xfer is queued. If the timer expires, release
- *         the rpipe [see rpipe_ep_disable()].
- *
- *     (b) when looking for free rpipes to attach [rpipe_get_by_ep()],
- *         when none are found go over the list, check their endpoint
- *         and their activity record (if no last-xfer-done-ts in the
- *         last x seconds) take it
- *
- *     However, due to the fact that we have a set of limited
- *     resources (max-segments-at-the-same-time per xfer,
- *     xfers-per-ripe, blocks-per-rpipe, rpipes-per-host), at the end
- *     we are going to have to rebuild all this based on an scheduler,
- *     to where we have a list of transactions to do and based on the
- *     availability of the different required components (blocks,
- *     rpipes, segment slots, etc), we go scheduling them. Painful.
- */
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/hash.h>
-#include <linux/ratelimit.h>
-#include <linux/export.h>
-#include <linux/scatterlist.h>
-
-#include "wa-hc.h"
-#include "wusbhc.h"
-
-enum {
-       /* [WUSB] section 8.3.3 allocates 7 bits for the segment index. */
-       WA_SEGS_MAX = 128,
-};
-
-enum wa_seg_status {
-       WA_SEG_NOTREADY,
-       WA_SEG_READY,
-       WA_SEG_DELAYED,
-       WA_SEG_SUBMITTED,
-       WA_SEG_PENDING,
-       WA_SEG_DTI_PENDING,
-       WA_SEG_DONE,
-       WA_SEG_ERROR,
-       WA_SEG_ABORTED,
-};
-
-static void wa_xfer_delayed_run(struct wa_rpipe *);
-static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting);
-
-/*
- * Life cycle governed by 'struct urb' (the refcount of the struct is
- * that of the 'struct urb' and usb_free_urb() would free the whole
- * struct).
- */
-struct wa_seg {
-       struct urb tr_urb;              /* transfer request urb. */
-       struct urb *isoc_pack_desc_urb; /* for isoc packet descriptor. */
-       struct urb *dto_urb;            /* for data output. */
-       struct list_head list_node;     /* for rpipe->req_list */
-       struct wa_xfer *xfer;           /* out xfer */
-       u8 index;                       /* which segment we are */
-       int isoc_frame_count;   /* number of isoc frames in this segment. */
-       int isoc_frame_offset;  /* starting frame offset in the xfer URB. */
-       /* Isoc frame that the current transfer buffer corresponds to. */
-       int isoc_frame_index;
-       int isoc_size;  /* size of all isoc frames sent by this seg. */
-       enum wa_seg_status status;
-       ssize_t result;                 /* bytes xfered or error */
-       struct wa_xfer_hdr xfer_hdr;
-};
-
-static inline void wa_seg_init(struct wa_seg *seg)
-{
-       usb_init_urb(&seg->tr_urb);
-
-       /* set the remaining memory to 0. */
-       memset(((void *)seg) + sizeof(seg->tr_urb), 0,
-               sizeof(*seg) - sizeof(seg->tr_urb));
-}
-
-/*
- * Protected by xfer->lock
- *
- */
-struct wa_xfer {
-       struct kref refcnt;
-       struct list_head list_node;
-       spinlock_t lock;
-       u32 id;
-
-       struct wahc *wa;                /* Wire adapter we are plugged to */
-       struct usb_host_endpoint *ep;
-       struct urb *urb;                /* URB we are transferring for */
-       struct wa_seg **seg;            /* transfer segments */
-       u8 segs, segs_submitted, segs_done;
-       unsigned is_inbound:1;
-       unsigned is_dma:1;
-       size_t seg_size;
-       int result;
-
-       gfp_t gfp;                      /* allocation mask */
-
-       struct wusb_dev *wusb_dev;      /* for activity timestamps */
-};
-
-static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer,
-       struct wa_seg *seg, int curr_iso_frame);
-static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
-               int starting_index, enum wa_seg_status status);
-
-static inline void wa_xfer_init(struct wa_xfer *xfer)
-{
-       kref_init(&xfer->refcnt);
-       INIT_LIST_HEAD(&xfer->list_node);
-       spin_lock_init(&xfer->lock);
-}
-
-/*
- * Destroy a transfer structure
- *
- * Note that freeing xfer->seg[cnt]->tr_urb will free the containing
- * xfer->seg[cnt] memory that was allocated by __wa_xfer_setup_segs.
- */
-static void wa_xfer_destroy(struct kref *_xfer)
-{
-       struct wa_xfer *xfer = container_of(_xfer, struct wa_xfer, refcnt);
-       if (xfer->seg) {
-               unsigned cnt;
-               for (cnt = 0; cnt < xfer->segs; cnt++) {
-                       struct wa_seg *seg = xfer->seg[cnt];
-                       if (seg) {
-                               usb_free_urb(seg->isoc_pack_desc_urb);
-                               if (seg->dto_urb) {
-                                       kfree(seg->dto_urb->sg);
-                                       usb_free_urb(seg->dto_urb);
-                               }
-                               usb_free_urb(&seg->tr_urb);
-                       }
-               }
-               kfree(xfer->seg);
-       }
-       kfree(xfer);
-}
-
-static void wa_xfer_get(struct wa_xfer *xfer)
-{
-       kref_get(&xfer->refcnt);
-}
-
-static void wa_xfer_put(struct wa_xfer *xfer)
-{
-       kref_put(&xfer->refcnt, wa_xfer_destroy);
-}
-
-/*
- * Try to get exclusive access to the DTO endpoint resource.  Return true
- * if successful.
- */
-static inline int __wa_dto_try_get(struct wahc *wa)
-{
-       return (test_and_set_bit(0, &wa->dto_in_use) == 0);
-}
-
-/* Release the DTO endpoint resource. */
-static inline void __wa_dto_put(struct wahc *wa)
-{
-       clear_bit_unlock(0, &wa->dto_in_use);
-}
-
-/* Service RPIPEs that are waiting on the DTO resource. */
-static void wa_check_for_delayed_rpipes(struct wahc *wa)
-{
-       unsigned long flags;
-       int dto_waiting = 0;
-       struct wa_rpipe *rpipe;
-
-       spin_lock_irqsave(&wa->rpipe_lock, flags);
-       while (!list_empty(&wa->rpipe_delayed_list) && !dto_waiting) {
-               rpipe = list_first_entry(&wa->rpipe_delayed_list,
-                               struct wa_rpipe, list_node);
-               __wa_xfer_delayed_run(rpipe, &dto_waiting);
-               /* remove this RPIPE from the list if it is not waiting. */
-               if (!dto_waiting) {
-                       pr_debug("%s: RPIPE %d serviced and removed from delayed list.\n",
-                               __func__,
-                               le16_to_cpu(rpipe->descr.wRPipeIndex));
-                       list_del_init(&rpipe->list_node);
-               }
-       }
-       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
-}
-
-/* add this RPIPE to the end of the delayed RPIPE list. */
-static void wa_add_delayed_rpipe(struct wahc *wa, struct wa_rpipe *rpipe)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&wa->rpipe_lock, flags);
-       /* add rpipe to the list if it is not already on it. */
-       if (list_empty(&rpipe->list_node)) {
-               pr_debug("%s: adding RPIPE %d to the delayed list.\n",
-                       __func__, le16_to_cpu(rpipe->descr.wRPipeIndex));
-               list_add_tail(&rpipe->list_node, &wa->rpipe_delayed_list);
-       }
-       spin_unlock_irqrestore(&wa->rpipe_lock, flags);
-}
-
-/*
- * xfer is referenced
- *
- * xfer->lock has to be unlocked
- *
- * We take xfer->lock for setting the result; this is a barrier
- * against drivers/usb/core/hcd.c:unlink1() being called after we call
- * usb_hcd_giveback_urb() and wa_urb_dequeue() trying to get a
- * reference to the transfer.
- */
-static void wa_xfer_giveback(struct wa_xfer *xfer)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&xfer->wa->xfer_list_lock, flags);
-       list_del_init(&xfer->list_node);
-       usb_hcd_unlink_urb_from_ep(&(xfer->wa->wusb->usb_hcd), xfer->urb);
-       spin_unlock_irqrestore(&xfer->wa->xfer_list_lock, flags);
-       /* FIXME: segmentation broken -- kills DWA */
-       wusbhc_giveback_urb(xfer->wa->wusb, xfer->urb, xfer->result);
-       wa_put(xfer->wa);
-       wa_xfer_put(xfer);
-}
-
-/*
- * xfer is referenced
- *
- * xfer->lock has to be unlocked
- */
-static void wa_xfer_completion(struct wa_xfer *xfer)
-{
-       if (xfer->wusb_dev)
-               wusb_dev_put(xfer->wusb_dev);
-       rpipe_put(xfer->ep->hcpriv);
-       wa_xfer_giveback(xfer);
-}
-
-/*
- * Initialize a transfer's ID
- *
- * We need to use a sequential number; if we use the pointer or the
- * hash of the pointer, it can repeat over sequential transfers and
- * then it will confuse the HWA....wonder why in hell they put a 32
- * bit handle in there then.
- */
-static void wa_xfer_id_init(struct wa_xfer *xfer)
-{
-       xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count);
-}
-
-/* Return the xfer's ID. */
-static inline u32 wa_xfer_id(struct wa_xfer *xfer)
-{
-       return xfer->id;
-}
-
-/* Return the xfer's ID in transport format (little endian). */
-static inline __le32 wa_xfer_id_le32(struct wa_xfer *xfer)
-{
-       return cpu_to_le32(xfer->id);
-}
-
-/*
- * If transfer is done, wrap it up and return true
- *
- * xfer->lock has to be locked
- */
-static unsigned __wa_xfer_is_done(struct wa_xfer *xfer)
-{
-       struct device *dev = &xfer->wa->usb_iface->dev;
-       unsigned result, cnt;
-       struct wa_seg *seg;
-       struct urb *urb = xfer->urb;
-       unsigned found_short = 0;
-
-       result = xfer->segs_done == xfer->segs_submitted;
-       if (result == 0)
-               goto out;
-       urb->actual_length = 0;
-       for (cnt = 0; cnt < xfer->segs; cnt++) {
-               seg = xfer->seg[cnt];
-               switch (seg->status) {
-               case WA_SEG_DONE:
-                       if (found_short && seg->result > 0) {
-                               dev_dbg(dev, "xfer %p ID %08X#%u: bad short segments (%zu)\n",
-                                       xfer, wa_xfer_id(xfer), cnt,
-                                       seg->result);
-                               urb->status = -EINVAL;
-                               goto out;
-                       }
-                       urb->actual_length += seg->result;
-                       if (!(usb_pipeisoc(xfer->urb->pipe))
-                               && seg->result < xfer->seg_size
-                           && cnt != xfer->segs-1)
-                               found_short = 1;
-                       dev_dbg(dev, "xfer %p ID %08X#%u: DONE short %d "
-                               "result %zu urb->actual_length %d\n",
-                               xfer, wa_xfer_id(xfer), seg->index, found_short,
-                               seg->result, urb->actual_length);
-                       break;
-               case WA_SEG_ERROR:
-                       xfer->result = seg->result;
-                       dev_dbg(dev, "xfer %p ID %08X#%u: ERROR result %zi(0x%08zX)\n",
-                               xfer, wa_xfer_id(xfer), seg->index, seg->result,
-                               seg->result);
-                       goto out;
-               case WA_SEG_ABORTED:
-                       xfer->result = seg->result;
-                       dev_dbg(dev, "xfer %p ID %08X#%u: ABORTED result %zi(0x%08zX)\n",
-                               xfer, wa_xfer_id(xfer), seg->index, seg->result,
-                               seg->result);
-                       goto out;
-               default:
-                       dev_warn(dev, "xfer %p ID %08X#%u: is_done bad state %d\n",
-                                xfer, wa_xfer_id(xfer), cnt, seg->status);
-                       xfer->result = -EINVAL;
-                       goto out;
-               }
-       }
-       xfer->result = 0;
-out:
-       return result;
-}
-
-/*
- * Mark the given segment as done.  Return true if this completes the xfer.
- * This should only be called for segs that have been submitted to an RPIPE.
- * Delayed segs are not marked as submitted so they do not need to be marked
- * as done when cleaning up.
- *
- * xfer->lock has to be locked
- */
-static unsigned __wa_xfer_mark_seg_as_done(struct wa_xfer *xfer,
-       struct wa_seg *seg, enum wa_seg_status status)
-{
-       seg->status = status;
-       xfer->segs_done++;
-
-       /* check for done. */
-       return __wa_xfer_is_done(xfer);
-}
-
-/*
- * Search for a transfer list ID on the HCD's URB list
- *
- * For 32 bit architectures, we use the pointer itself; for 64 bits, a
- * 32-bit hash of the pointer.
- *
- * @returns NULL if not found.
- */
-static struct wa_xfer *wa_xfer_get_by_id(struct wahc *wa, u32 id)
-{
-       unsigned long flags;
-       struct wa_xfer *xfer_itr;
-       spin_lock_irqsave(&wa->xfer_list_lock, flags);
-       list_for_each_entry(xfer_itr, &wa->xfer_list, list_node) {
-               if (id == xfer_itr->id) {
-                       wa_xfer_get(xfer_itr);
-                       goto out;
-               }
-       }
-       xfer_itr = NULL;
-out:
-       spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
-       return xfer_itr;
-}
-
-struct wa_xfer_abort_buffer {
-       struct urb urb;
-       struct wahc *wa;
-       struct wa_xfer_abort cmd;
-};
-
-static void __wa_xfer_abort_cb(struct urb *urb)
-{
-       struct wa_xfer_abort_buffer *b = urb->context;
-       struct wahc *wa = b->wa;
-
-       /*
-        * If the abort request URB failed, then the HWA did not get the abort
-        * command.  Forcibly clean up the xfer without waiting for a Transfer
-        * Result from the HWA.
-        */
-       if (urb->status < 0) {
-               struct wa_xfer *xfer;
-               struct device *dev = &wa->usb_iface->dev;
-
-               xfer = wa_xfer_get_by_id(wa, le32_to_cpu(b->cmd.dwTransferID));
-               dev_err(dev, "%s: Transfer Abort request failed. result: %d\n",
-                       __func__, urb->status);
-               if (xfer) {
-                       unsigned long flags;
-                       int done, seg_index = 0;
-                       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-
-                       dev_err(dev, "%s: cleaning up xfer %p ID 0x%08X.\n",
-                               __func__, xfer, wa_xfer_id(xfer));
-                       spin_lock_irqsave(&xfer->lock, flags);
-                       /* skip done segs. */
-                       while (seg_index < xfer->segs) {
-                               struct wa_seg *seg = xfer->seg[seg_index];
-
-                               if ((seg->status == WA_SEG_DONE) ||
-                                       (seg->status == WA_SEG_ERROR)) {
-                                       ++seg_index;
-                               } else {
-                                       break;
-                               }
-                       }
-                       /* mark remaining segs as aborted. */
-                       wa_complete_remaining_xfer_segs(xfer, seg_index,
-                               WA_SEG_ABORTED);
-                       done = __wa_xfer_is_done(xfer);
-                       spin_unlock_irqrestore(&xfer->lock, flags);
-                       if (done)
-                               wa_xfer_completion(xfer);
-                       wa_xfer_delayed_run(rpipe);
-                       wa_xfer_put(xfer);
-               } else {
-                       dev_err(dev, "%s: xfer ID 0x%08X already gone.\n",
-                                __func__, le32_to_cpu(b->cmd.dwTransferID));
-               }
-       }
-
-       wa_put(wa);     /* taken in __wa_xfer_abort */
-       usb_put_urb(&b->urb);
-}
-
-/*
- * Aborts an ongoing transaction
- *
- * Assumes the transfer is referenced and locked and in a submitted
- * state (mainly that there is an endpoint/rpipe assigned).
- *
- * The callback (see above) does nothing but freeing up the data by
- * putting the URB. Because the URB is allocated at the head of the
- * struct, the whole space we allocated is kfreed. *
- */
-static int __wa_xfer_abort(struct wa_xfer *xfer)
-{
-       int result = -ENOMEM;
-       struct device *dev = &xfer->wa->usb_iface->dev;
-       struct wa_xfer_abort_buffer *b;
-       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-
-       b = kmalloc(sizeof(*b), GFP_ATOMIC);
-       if (b == NULL)
-               goto error_kmalloc;
-       b->cmd.bLength =  sizeof(b->cmd);
-       b->cmd.bRequestType = WA_XFER_ABORT;
-       b->cmd.wRPipe = rpipe->descr.wRPipeIndex;
-       b->cmd.dwTransferID = wa_xfer_id_le32(xfer);
-       b->wa = wa_get(xfer->wa);
-
-       usb_init_urb(&b->urb);
-       usb_fill_bulk_urb(&b->urb, xfer->wa->usb_dev,
-               usb_sndbulkpipe(xfer->wa->usb_dev,
-                               xfer->wa->dto_epd->bEndpointAddress),
-               &b->cmd, sizeof(b->cmd), __wa_xfer_abort_cb, b);
-       result = usb_submit_urb(&b->urb, GFP_ATOMIC);
-       if (result < 0)
-               goto error_submit;
-       return result;                          /* callback frees! */
-
-
-error_submit:
-       wa_put(xfer->wa);
-       if (printk_ratelimit())
-               dev_err(dev, "xfer %p: Can't submit abort request: %d\n",
-                       xfer, result);
-       kfree(b);
-error_kmalloc:
-       return result;
-
-}
-
-/*
- * Calculate the number of isoc frames starting from isoc_frame_offset
- * that will fit a in transfer segment.
- */
-static int __wa_seg_calculate_isoc_frame_count(struct wa_xfer *xfer,
-       int isoc_frame_offset, int *total_size)
-{
-       int segment_size = 0, frame_count = 0;
-       int index = isoc_frame_offset;
-       struct usb_iso_packet_descriptor *iso_frame_desc =
-               xfer->urb->iso_frame_desc;
-
-       while ((index < xfer->urb->number_of_packets)
-               && ((segment_size + iso_frame_desc[index].length)
-                               <= xfer->seg_size)) {
-               /*
-                * For Alereon HWA devices, only include an isoc frame in an
-                * out segment if it is physically contiguous with the previous
-                * frame.  This is required because those devices expect
-                * the isoc frames to be sent as a single USB transaction as
-                * opposed to one transaction per frame with standard HWA.
-                */
-               if ((xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
-                       && (xfer->is_inbound == 0)
-                       && (index > isoc_frame_offset)
-                       && ((iso_frame_desc[index - 1].offset +
-                               iso_frame_desc[index - 1].length) !=
-                               iso_frame_desc[index].offset))
-                       break;
-
-               /* this frame fits. count it. */
-               ++frame_count;
-               segment_size += iso_frame_desc[index].length;
-
-               /* move to the next isoc frame. */
-               ++index;
-       }
-
-       *total_size = segment_size;
-       return frame_count;
-}
-
-/*
- *
- * @returns < 0 on error, transfer segment request size if ok
- */
-static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer,
-                                    enum wa_xfer_type *pxfer_type)
-{
-       ssize_t result;
-       struct device *dev = &xfer->wa->usb_iface->dev;
-       size_t maxpktsize;
-       struct urb *urb = xfer->urb;
-       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-
-       switch (rpipe->descr.bmAttribute & 0x3) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               *pxfer_type = WA_XFER_TYPE_CTL;
-               result = sizeof(struct wa_xfer_ctl);
-               break;
-       case USB_ENDPOINT_XFER_INT:
-       case USB_ENDPOINT_XFER_BULK:
-               *pxfer_type = WA_XFER_TYPE_BI;
-               result = sizeof(struct wa_xfer_bi);
-               break;
-       case USB_ENDPOINT_XFER_ISOC:
-               *pxfer_type = WA_XFER_TYPE_ISO;
-               result = sizeof(struct wa_xfer_hwaiso);
-               break;
-       default:
-               /* never happens */
-               BUG();
-               result = -EINVAL;       /* shut gcc up */
-       }
-       xfer->is_inbound = urb->pipe & USB_DIR_IN ? 1 : 0;
-       xfer->is_dma = urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? 1 : 0;
-
-       maxpktsize = le16_to_cpu(rpipe->descr.wMaxPacketSize);
-       xfer->seg_size = le16_to_cpu(rpipe->descr.wBlocks)
-               * 1 << (xfer->wa->wa_descr->bRPipeBlockSize - 1);
-       /* Compute the segment size and make sure it is a multiple of
-        * the maxpktsize (WUSB1.0[8.3.3.1])...not really too much of
-        * a check (FIXME) */
-       if (xfer->seg_size < maxpktsize) {
-               dev_err(dev,
-                       "HW BUG? seg_size %zu smaller than maxpktsize %zu\n",
-                       xfer->seg_size, maxpktsize);
-               result = -EINVAL;
-               goto error;
-       }
-       xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize;
-       if ((rpipe->descr.bmAttribute & 0x3) == USB_ENDPOINT_XFER_ISOC) {
-               int index = 0;
-
-               xfer->segs = 0;
-               /*
-                * loop over urb->number_of_packets to determine how many
-                * xfer segments will be needed to send the isoc frames.
-                */
-               while (index < urb->number_of_packets) {
-                       int seg_size; /* don't care. */
-                       index += __wa_seg_calculate_isoc_frame_count(xfer,
-                                       index, &seg_size);
-                       ++xfer->segs;
-               }
-       } else {
-               xfer->segs = DIV_ROUND_UP(urb->transfer_buffer_length,
-                                               xfer->seg_size);
-               if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL)
-                       xfer->segs = 1;
-       }
-
-       if (xfer->segs > WA_SEGS_MAX) {
-               dev_err(dev, "BUG? oops, number of segments %zu bigger than %d\n",
-                       (urb->transfer_buffer_length/xfer->seg_size),
-                       WA_SEGS_MAX);
-               result = -EINVAL;
-               goto error;
-       }
-error:
-       return result;
-}
-
-static void __wa_setup_isoc_packet_descr(
-               struct wa_xfer_packet_info_hwaiso *packet_desc,
-               struct wa_xfer *xfer,
-               struct wa_seg *seg) {
-       struct usb_iso_packet_descriptor *iso_frame_desc =
-               xfer->urb->iso_frame_desc;
-       int frame_index;
-
-       /* populate isoc packet descriptor. */
-       packet_desc->bPacketType = WA_XFER_ISO_PACKET_INFO;
-       packet_desc->wLength = cpu_to_le16(struct_size(packet_desc,
-                                          PacketLength,
-                                          seg->isoc_frame_count));
-       for (frame_index = 0; frame_index < seg->isoc_frame_count;
-               ++frame_index) {
-               int offset_index = frame_index + seg->isoc_frame_offset;
-               packet_desc->PacketLength[frame_index] =
-                       cpu_to_le16(iso_frame_desc[offset_index].length);
-       }
-}
-
-
-/* Fill in the common request header and xfer-type specific data. */
-static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer,
-                                struct wa_xfer_hdr *xfer_hdr0,
-                                enum wa_xfer_type xfer_type,
-                                size_t xfer_hdr_size)
-{
-       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-       struct wa_seg *seg = xfer->seg[0];
-
-       xfer_hdr0 = &seg->xfer_hdr;
-       xfer_hdr0->bLength = xfer_hdr_size;
-       xfer_hdr0->bRequestType = xfer_type;
-       xfer_hdr0->wRPipe = rpipe->descr.wRPipeIndex;
-       xfer_hdr0->dwTransferID = wa_xfer_id_le32(xfer);
-       xfer_hdr0->bTransferSegment = 0;
-       switch (xfer_type) {
-       case WA_XFER_TYPE_CTL: {
-               struct wa_xfer_ctl *xfer_ctl =
-                       container_of(xfer_hdr0, struct wa_xfer_ctl, hdr);
-               xfer_ctl->bmAttribute = xfer->is_inbound ? 1 : 0;
-               memcpy(&xfer_ctl->baSetupData, xfer->urb->setup_packet,
-                      sizeof(xfer_ctl->baSetupData));
-               break;
-       }
-       case WA_XFER_TYPE_BI:
-               break;
-       case WA_XFER_TYPE_ISO: {
-               struct wa_xfer_hwaiso *xfer_iso =
-                       container_of(xfer_hdr0, struct wa_xfer_hwaiso, hdr);
-               struct wa_xfer_packet_info_hwaiso *packet_desc =
-                       ((void *)xfer_iso) + xfer_hdr_size;
-
-               /* populate the isoc section of the transfer request. */
-               xfer_iso->dwNumOfPackets = cpu_to_le32(seg->isoc_frame_count);
-               /* populate isoc packet descriptor. */
-               __wa_setup_isoc_packet_descr(packet_desc, xfer, seg);
-               break;
-       }
-       default:
-               BUG();
-       };
-}
-
-/*
- * Callback for the OUT data phase of the segment request
- *
- * Check wa_seg_tr_cb(); most comments also apply here because this
- * function does almost the same thing and they work closely
- * together.
- *
- * If the seg request has failed but this DTO phase has succeeded,
- * wa_seg_tr_cb() has already failed the segment and moved the
- * status to WA_SEG_ERROR, so this will go through 'case 0' and
- * effectively do nothing.
- */
-static void wa_seg_dto_cb(struct urb *urb)
-{
-       struct wa_seg *seg = urb->context;
-       struct wa_xfer *xfer = seg->xfer;
-       struct wahc *wa;
-       struct device *dev;
-       struct wa_rpipe *rpipe;
-       unsigned long flags;
-       unsigned rpipe_ready = 0;
-       int data_send_done = 1, release_dto = 0, holding_dto = 0;
-       u8 done = 0;
-       int result;
-
-       /* free the sg if it was used. */
-       kfree(urb->sg);
-       urb->sg = NULL;
-
-       spin_lock_irqsave(&xfer->lock, flags);
-       wa = xfer->wa;
-       dev = &wa->usb_iface->dev;
-       if (usb_pipeisoc(xfer->urb->pipe)) {
-               /* Alereon HWA sends all isoc frames in a single transfer. */
-               if (wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
-                       seg->isoc_frame_index += seg->isoc_frame_count;
-               else
-                       seg->isoc_frame_index += 1;
-               if (seg->isoc_frame_index < seg->isoc_frame_count) {
-                       data_send_done = 0;
-                       holding_dto = 1; /* checked in error cases. */
-                       /*
-                        * if this is the last isoc frame of the segment, we
-                        * can release DTO after sending this frame.
-                        */
-                       if ((seg->isoc_frame_index + 1) >=
-                               seg->isoc_frame_count)
-                               release_dto = 1;
-               }
-               dev_dbg(dev, "xfer 0x%08X#%u: isoc frame = %d, holding_dto = %d, release_dto = %d.\n",
-                       wa_xfer_id(xfer), seg->index, seg->isoc_frame_index,
-                       holding_dto, release_dto);
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-
-       switch (urb->status) {
-       case 0:
-               spin_lock_irqsave(&xfer->lock, flags);
-               seg->result += urb->actual_length;
-               if (data_send_done) {
-                       dev_dbg(dev, "xfer 0x%08X#%u: data out done (%zu bytes)\n",
-                               wa_xfer_id(xfer), seg->index, seg->result);
-                       if (seg->status < WA_SEG_PENDING)
-                               seg->status = WA_SEG_PENDING;
-               } else {
-                       /* should only hit this for isoc xfers. */
-                       /*
-                        * Populate the dto URB with the next isoc frame buffer,
-                        * send the URB and release DTO if we no longer need it.
-                        */
-                        __wa_populate_dto_urb_isoc(xfer, seg,
-                               seg->isoc_frame_offset + seg->isoc_frame_index);
-
-                       /* resubmit the URB with the next isoc frame. */
-                       /* take a ref on resubmit. */
-                       wa_xfer_get(xfer);
-                       result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
-                       if (result < 0) {
-                               dev_err(dev, "xfer 0x%08X#%u: DTO submit failed: %d\n",
-                                      wa_xfer_id(xfer), seg->index, result);
-                               spin_unlock_irqrestore(&xfer->lock, flags);
-                               goto error_dto_submit;
-                       }
-               }
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (release_dto) {
-                       __wa_dto_put(wa);
-                       wa_check_for_delayed_rpipes(wa);
-               }
-               break;
-       case -ECONNRESET:       /* URB unlinked; no need to do anything */
-       case -ENOENT:           /* as it was done by the who unlinked us */
-               if (holding_dto) {
-                       __wa_dto_put(wa);
-                       wa_check_for_delayed_rpipes(wa);
-               }
-               break;
-       default:                /* Other errors ... */
-               dev_err(dev, "xfer 0x%08X#%u: data out error %d\n",
-                       wa_xfer_id(xfer), seg->index, urb->status);
-               goto error_default;
-       }
-
-       /* taken when this URB was submitted. */
-       wa_xfer_put(xfer);
-       return;
-
-error_dto_submit:
-       /* taken on resubmit attempt. */
-       wa_xfer_put(xfer);
-error_default:
-       spin_lock_irqsave(&xfer->lock, flags);
-       rpipe = xfer->ep->hcpriv;
-       if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
-                   EDC_ERROR_TIMEFRAME)){
-               dev_err(dev, "DTO: URB max acceptable errors exceeded, resetting device\n");
-               wa_reset_all(wa);
-       }
-       if (seg->status != WA_SEG_ERROR) {
-               seg->result = urb->status;
-               __wa_xfer_abort(xfer);
-               rpipe_ready = rpipe_avail_inc(rpipe);
-               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (holding_dto) {
-               __wa_dto_put(wa);
-               wa_check_for_delayed_rpipes(wa);
-       }
-       if (done)
-               wa_xfer_completion(xfer);
-       if (rpipe_ready)
-               wa_xfer_delayed_run(rpipe);
-       /* taken when this URB was submitted. */
-       wa_xfer_put(xfer);
-}
-
-/*
- * Callback for the isoc packet descriptor phase of the segment request
- *
- * Check wa_seg_tr_cb(); most comments also apply here because this
- * function does almost the same thing and they work closely
- * together.
- *
- * If the seg request has failed but this phase has succeeded,
- * wa_seg_tr_cb() has already failed the segment and moved the
- * status to WA_SEG_ERROR, so this will go through 'case 0' and
- * effectively do nothing.
- */
-static void wa_seg_iso_pack_desc_cb(struct urb *urb)
-{
-       struct wa_seg *seg = urb->context;
-       struct wa_xfer *xfer = seg->xfer;
-       struct wahc *wa;
-       struct device *dev;
-       struct wa_rpipe *rpipe;
-       unsigned long flags;
-       unsigned rpipe_ready = 0;
-       u8 done = 0;
-
-       switch (urb->status) {
-       case 0:
-               spin_lock_irqsave(&xfer->lock, flags);
-               wa = xfer->wa;
-               dev = &wa->usb_iface->dev;
-               dev_dbg(dev, "iso xfer %08X#%u: packet descriptor done\n",
-                       wa_xfer_id(xfer), seg->index);
-               if (xfer->is_inbound && seg->status < WA_SEG_PENDING)
-                       seg->status = WA_SEG_PENDING;
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               break;
-       case -ECONNRESET:       /* URB unlinked; no need to do anything */
-       case -ENOENT:           /* as it was done by the who unlinked us */
-               break;
-       default:                /* Other errors ... */
-               spin_lock_irqsave(&xfer->lock, flags);
-               wa = xfer->wa;
-               dev = &wa->usb_iface->dev;
-               rpipe = xfer->ep->hcpriv;
-               pr_err_ratelimited("iso xfer %08X#%u: packet descriptor error %d\n",
-                               wa_xfer_id(xfer), seg->index, urb->status);
-               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)){
-                       dev_err(dev, "iso xfer: URB max acceptable errors exceeded, resetting device\n");
-                       wa_reset_all(wa);
-               }
-               if (seg->status != WA_SEG_ERROR) {
-                       usb_unlink_urb(seg->dto_urb);
-                       seg->result = urb->status;
-                       __wa_xfer_abort(xfer);
-                       rpipe_ready = rpipe_avail_inc(rpipe);
-                       done = __wa_xfer_mark_seg_as_done(xfer, seg,
-                                       WA_SEG_ERROR);
-               }
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (done)
-                       wa_xfer_completion(xfer);
-               if (rpipe_ready)
-                       wa_xfer_delayed_run(rpipe);
-       }
-       /* taken when this URB was submitted. */
-       wa_xfer_put(xfer);
-}
-
-/*
- * Callback for the segment request
- *
- * If successful transition state (unless already transitioned or
- * outbound transfer); otherwise, take a note of the error, mark this
- * segment done and try completion.
- *
- * Note we don't access until we are sure that the transfer hasn't
- * been cancelled (ECONNRESET, ENOENT), which could mean that
- * seg->xfer could be already gone.
- *
- * We have to check before setting the status to WA_SEG_PENDING
- * because sometimes the xfer result callback arrives before this
- * callback (geeeeeeze), so it might happen that we are already in
- * another state. As well, we don't set it if the transfer is not inbound,
- * as in that case, wa_seg_dto_cb will do it when the OUT data phase
- * finishes.
- */
-static void wa_seg_tr_cb(struct urb *urb)
-{
-       struct wa_seg *seg = urb->context;
-       struct wa_xfer *xfer = seg->xfer;
-       struct wahc *wa;
-       struct device *dev;
-       struct wa_rpipe *rpipe;
-       unsigned long flags;
-       unsigned rpipe_ready;
-       u8 done = 0;
-
-       switch (urb->status) {
-       case 0:
-               spin_lock_irqsave(&xfer->lock, flags);
-               wa = xfer->wa;
-               dev = &wa->usb_iface->dev;
-               dev_dbg(dev, "xfer %p ID 0x%08X#%u: request done\n",
-                       xfer, wa_xfer_id(xfer), seg->index);
-               if (xfer->is_inbound &&
-                       seg->status < WA_SEG_PENDING &&
-                       !(usb_pipeisoc(xfer->urb->pipe)))
-                       seg->status = WA_SEG_PENDING;
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               break;
-       case -ECONNRESET:       /* URB unlinked; no need to do anything */
-       case -ENOENT:           /* as it was done by the who unlinked us */
-               break;
-       default:                /* Other errors ... */
-               spin_lock_irqsave(&xfer->lock, flags);
-               wa = xfer->wa;
-               dev = &wa->usb_iface->dev;
-               rpipe = xfer->ep->hcpriv;
-               if (printk_ratelimit())
-                       dev_err(dev, "xfer %p ID 0x%08X#%u: request error %d\n",
-                               xfer, wa_xfer_id(xfer), seg->index,
-                               urb->status);
-               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)){
-                       dev_err(dev, "DTO: URB max acceptable errors "
-                               "exceeded, resetting device\n");
-                       wa_reset_all(wa);
-               }
-               usb_unlink_urb(seg->isoc_pack_desc_urb);
-               usb_unlink_urb(seg->dto_urb);
-               seg->result = urb->status;
-               __wa_xfer_abort(xfer);
-               rpipe_ready = rpipe_avail_inc(rpipe);
-               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (done)
-                       wa_xfer_completion(xfer);
-               if (rpipe_ready)
-                       wa_xfer_delayed_run(rpipe);
-       }
-       /* taken when this URB was submitted. */
-       wa_xfer_put(xfer);
-}
-
-/*
- * Allocate an SG list to store bytes_to_transfer bytes and copy the
- * subset of the in_sg that matches the buffer subset
- * we are about to transfer.
- */
-static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,
-       const unsigned int bytes_transferred,
-       const unsigned int bytes_to_transfer, int *out_num_sgs)
-{
-       struct scatterlist *out_sg;
-       unsigned int bytes_processed = 0, offset_into_current_page_data = 0,
-               nents;
-       struct scatterlist *current_xfer_sg = in_sg;
-       struct scatterlist *current_seg_sg, *last_seg_sg;
-
-       /* skip previously transferred pages. */
-       while ((current_xfer_sg) &&
-                       (bytes_processed < bytes_transferred)) {
-               bytes_processed += current_xfer_sg->length;
-
-               /* advance the sg if current segment starts on or past the
-                       next page. */
-               if (bytes_processed <= bytes_transferred)
-                       current_xfer_sg = sg_next(current_xfer_sg);
-       }
-
-       /* the data for the current segment starts in current_xfer_sg.
-               calculate the offset. */
-       if (bytes_processed > bytes_transferred) {
-               offset_into_current_page_data = current_xfer_sg->length -
-                       (bytes_processed - bytes_transferred);
-       }
-
-       /* calculate the number of pages needed by this segment. */
-       nents = DIV_ROUND_UP((bytes_to_transfer +
-               offset_into_current_page_data +
-               current_xfer_sg->offset),
-               PAGE_SIZE);
-
-       out_sg = kmalloc((sizeof(struct scatterlist) * nents), GFP_ATOMIC);
-       if (out_sg) {
-               sg_init_table(out_sg, nents);
-
-               /* copy the portion of the incoming SG that correlates to the
-                * data to be transferred by this segment to the segment SG. */
-               last_seg_sg = current_seg_sg = out_sg;
-               bytes_processed = 0;
-
-               /* reset nents and calculate the actual number of sg entries
-                       needed. */
-               nents = 0;
-               while ((bytes_processed < bytes_to_transfer) &&
-                               current_seg_sg && current_xfer_sg) {
-                       unsigned int page_len = min((current_xfer_sg->length -
-                               offset_into_current_page_data),
-                               (bytes_to_transfer - bytes_processed));
-
-                       sg_set_page(current_seg_sg, sg_page(current_xfer_sg),
-                               page_len,
-                               current_xfer_sg->offset +
-                               offset_into_current_page_data);
-
-                       bytes_processed += page_len;
-
-                       last_seg_sg = current_seg_sg;
-                       current_seg_sg = sg_next(current_seg_sg);
-                       current_xfer_sg = sg_next(current_xfer_sg);
-
-                       /* only the first page may require additional offset. */
-                       offset_into_current_page_data = 0;
-                       nents++;
-               }
-
-               /* update num_sgs and terminate the list since we may have
-                *  concatenated pages. */
-               sg_mark_end(last_seg_sg);
-               *out_num_sgs = nents;
-       }
-
-       return out_sg;
-}
-
-/*
- * Populate DMA buffer info for the isoc dto urb.
- */
-static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer,
-       struct wa_seg *seg, int curr_iso_frame)
-{
-       seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-       seg->dto_urb->sg = NULL;
-       seg->dto_urb->num_sgs = 0;
-       /* dto urb buffer address pulled from iso_frame_desc. */
-       seg->dto_urb->transfer_dma = xfer->urb->transfer_dma +
-               xfer->urb->iso_frame_desc[curr_iso_frame].offset;
-       /* The Alereon HWA sends a single URB with all isoc segs. */
-       if (xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC)
-               seg->dto_urb->transfer_buffer_length = seg->isoc_size;
-       else
-               seg->dto_urb->transfer_buffer_length =
-                       xfer->urb->iso_frame_desc[curr_iso_frame].length;
-}
-
-/*
- * Populate buffer ptr and size, DMA buffer or SG list for the dto urb.
- */
-static int __wa_populate_dto_urb(struct wa_xfer *xfer,
-       struct wa_seg *seg, size_t buf_itr_offset, size_t buf_itr_size)
-{
-       int result = 0;
-
-       if (xfer->is_dma) {
-               seg->dto_urb->transfer_dma =
-                       xfer->urb->transfer_dma + buf_itr_offset;
-               seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-               seg->dto_urb->sg = NULL;
-               seg->dto_urb->num_sgs = 0;
-       } else {
-               /* do buffer or SG processing. */
-               seg->dto_urb->transfer_flags &=
-                       ~URB_NO_TRANSFER_DMA_MAP;
-               /* this should always be 0 before a resubmit. */
-               seg->dto_urb->num_mapped_sgs = 0;
-
-               if (xfer->urb->transfer_buffer) {
-                       seg->dto_urb->transfer_buffer =
-                               xfer->urb->transfer_buffer +
-                               buf_itr_offset;
-                       seg->dto_urb->sg = NULL;
-                       seg->dto_urb->num_sgs = 0;
-               } else {
-                       seg->dto_urb->transfer_buffer = NULL;
-
-                       /*
-                        * allocate an SG list to store seg_size bytes
-                        * and copy the subset of the xfer->urb->sg that
-                        * matches the buffer subset we are about to
-                        * read.
-                        */
-                       seg->dto_urb->sg = wa_xfer_create_subset_sg(
-                               xfer->urb->sg,
-                               buf_itr_offset, buf_itr_size,
-                               &(seg->dto_urb->num_sgs));
-                       if (!(seg->dto_urb->sg))
-                               result = -ENOMEM;
-               }
-       }
-       seg->dto_urb->transfer_buffer_length = buf_itr_size;
-
-       return result;
-}
-
-/*
- * Allocate the segs array and initialize each of them
- *
- * The segments are freed by wa_xfer_destroy() when the xfer use count
- * drops to zero; however, because each segment is given the same life
- * cycle as the USB URB it contains, it is actually freed by
- * usb_put_urb() on the contained USB URB (twisted, eh?).
- */
-static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)
-{
-       int result, cnt, isoc_frame_offset = 0;
-       size_t alloc_size = sizeof(*xfer->seg[0])
-               - sizeof(xfer->seg[0]->xfer_hdr) + xfer_hdr_size;
-       struct usb_device *usb_dev = xfer->wa->usb_dev;
-       const struct usb_endpoint_descriptor *dto_epd = xfer->wa->dto_epd;
-       struct wa_seg *seg;
-       size_t buf_itr, buf_size, buf_itr_size;
-
-       result = -ENOMEM;
-       xfer->seg = kcalloc(xfer->segs, sizeof(xfer->seg[0]), GFP_ATOMIC);
-       if (xfer->seg == NULL)
-               goto error_segs_kzalloc;
-       buf_itr = 0;
-       buf_size = xfer->urb->transfer_buffer_length;
-       for (cnt = 0; cnt < xfer->segs; cnt++) {
-               size_t iso_pkt_descr_size = 0;
-               int seg_isoc_frame_count = 0, seg_isoc_size = 0;
-
-               /*
-                * Adjust the size of the segment object to contain space for
-                * the isoc packet descriptor buffer.
-                */
-               if (usb_pipeisoc(xfer->urb->pipe)) {
-                       seg_isoc_frame_count =
-                               __wa_seg_calculate_isoc_frame_count(xfer,
-                                       isoc_frame_offset, &seg_isoc_size);
-
-                       iso_pkt_descr_size =
-                               sizeof(struct wa_xfer_packet_info_hwaiso) +
-                               (seg_isoc_frame_count * sizeof(__le16));
-               }
-               result = -ENOMEM;
-               seg = xfer->seg[cnt] = kmalloc(alloc_size + iso_pkt_descr_size,
-                                               GFP_ATOMIC);
-               if (seg == NULL)
-                       goto error_seg_kmalloc;
-               wa_seg_init(seg);
-               seg->xfer = xfer;
-               seg->index = cnt;
-               usb_fill_bulk_urb(&seg->tr_urb, usb_dev,
-                                 usb_sndbulkpipe(usb_dev,
-                                                 dto_epd->bEndpointAddress),
-                                 &seg->xfer_hdr, xfer_hdr_size,
-                                 wa_seg_tr_cb, seg);
-               buf_itr_size = min(buf_size, xfer->seg_size);
-
-               if (usb_pipeisoc(xfer->urb->pipe)) {
-                       seg->isoc_frame_count = seg_isoc_frame_count;
-                       seg->isoc_frame_offset = isoc_frame_offset;
-                       seg->isoc_size = seg_isoc_size;
-                       /* iso packet descriptor. */
-                       seg->isoc_pack_desc_urb =
-                                       usb_alloc_urb(0, GFP_ATOMIC);
-                       if (seg->isoc_pack_desc_urb == NULL)
-                               goto error_iso_pack_desc_alloc;
-                       /*
-                        * The buffer for the isoc packet descriptor starts
-                        * after the transfer request header in the
-                        * segment object memory buffer.
-                        */
-                       usb_fill_bulk_urb(
-                               seg->isoc_pack_desc_urb, usb_dev,
-                               usb_sndbulkpipe(usb_dev,
-                                       dto_epd->bEndpointAddress),
-                               (void *)(&seg->xfer_hdr) +
-                                       xfer_hdr_size,
-                               iso_pkt_descr_size,
-                               wa_seg_iso_pack_desc_cb, seg);
-
-                       /* adjust starting frame offset for next seg. */
-                       isoc_frame_offset += seg_isoc_frame_count;
-               }
-
-               if (xfer->is_inbound == 0 && buf_size > 0) {
-                       /* outbound data. */
-                       seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC);
-                       if (seg->dto_urb == NULL)
-                               goto error_dto_alloc;
-                       usb_fill_bulk_urb(
-                               seg->dto_urb, usb_dev,
-                               usb_sndbulkpipe(usb_dev,
-                                               dto_epd->bEndpointAddress),
-                               NULL, 0, wa_seg_dto_cb, seg);
-
-                       if (usb_pipeisoc(xfer->urb->pipe)) {
-                               /*
-                                * Fill in the xfer buffer information for the
-                                * first isoc frame.  Subsequent frames in this
-                                * segment will be filled in and sent from the
-                                * DTO completion routine, if needed.
-                                */
-                               __wa_populate_dto_urb_isoc(xfer, seg,
-                                       seg->isoc_frame_offset);
-                       } else {
-                               /* fill in the xfer buffer information. */
-                               result = __wa_populate_dto_urb(xfer, seg,
-                                                       buf_itr, buf_itr_size);
-                               if (result < 0)
-                                       goto error_seg_outbound_populate;
-
-                               buf_itr += buf_itr_size;
-                               buf_size -= buf_itr_size;
-                       }
-               }
-               seg->status = WA_SEG_READY;
-       }
-       return 0;
-
-       /*
-        * Free the memory for the current segment which failed to init.
-        * Use the fact that cnt is left at were it failed.  The remaining
-        * segments will be cleaned up by wa_xfer_destroy.
-        */
-error_seg_outbound_populate:
-       usb_free_urb(xfer->seg[cnt]->dto_urb);
-error_dto_alloc:
-       usb_free_urb(xfer->seg[cnt]->isoc_pack_desc_urb);
-error_iso_pack_desc_alloc:
-       kfree(xfer->seg[cnt]);
-       xfer->seg[cnt] = NULL;
-error_seg_kmalloc:
-error_segs_kzalloc:
-       return result;
-}
-
-/*
- * Allocates all the stuff needed to submit a transfer
- *
- * Breaks the whole data buffer in a list of segments, each one has a
- * structure allocated to it and linked in xfer->seg[index]
- *
- * FIXME: merge setup_segs() and the last part of this function, no
- *        need to do two for loops when we could run everything in a
- *        single one
- */
-static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb)
-{
-       int result;
-       struct device *dev = &xfer->wa->usb_iface->dev;
-       enum wa_xfer_type xfer_type = 0; /* shut up GCC */
-       size_t xfer_hdr_size, cnt, transfer_size;
-       struct wa_xfer_hdr *xfer_hdr0, *xfer_hdr;
-
-       result = __wa_xfer_setup_sizes(xfer, &xfer_type);
-       if (result < 0)
-               goto error_setup_sizes;
-       xfer_hdr_size = result;
-       result = __wa_xfer_setup_segs(xfer, xfer_hdr_size);
-       if (result < 0) {
-               dev_err(dev, "xfer %p: Failed to allocate %d segments: %d\n",
-                       xfer, xfer->segs, result);
-               goto error_setup_segs;
-       }
-       /* Fill the first header */
-       xfer_hdr0 = &xfer->seg[0]->xfer_hdr;
-       wa_xfer_id_init(xfer);
-       __wa_xfer_setup_hdr0(xfer, xfer_hdr0, xfer_type, xfer_hdr_size);
-
-       /* Fill remaining headers */
-       xfer_hdr = xfer_hdr0;
-       if (xfer_type == WA_XFER_TYPE_ISO) {
-               xfer_hdr0->dwTransferLength =
-                       cpu_to_le32(xfer->seg[0]->isoc_size);
-               for (cnt = 1; cnt < xfer->segs; cnt++) {
-                       struct wa_xfer_packet_info_hwaiso *packet_desc;
-                       struct wa_seg *seg = xfer->seg[cnt];
-                       struct wa_xfer_hwaiso *xfer_iso;
-
-                       xfer_hdr = &seg->xfer_hdr;
-                       xfer_iso = container_of(xfer_hdr,
-                                               struct wa_xfer_hwaiso, hdr);
-                       packet_desc = ((void *)xfer_hdr) + xfer_hdr_size;
-                       /*
-                        * Copy values from the 0th header. Segment specific
-                        * values are set below.
-                        */
-                       memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size);
-                       xfer_hdr->bTransferSegment = cnt;
-                       xfer_hdr->dwTransferLength =
-                               cpu_to_le32(seg->isoc_size);
-                       xfer_iso->dwNumOfPackets =
-                                       cpu_to_le32(seg->isoc_frame_count);
-                       __wa_setup_isoc_packet_descr(packet_desc, xfer, seg);
-                       seg->status = WA_SEG_READY;
-               }
-       } else {
-               transfer_size = urb->transfer_buffer_length;
-               xfer_hdr0->dwTransferLength = transfer_size > xfer->seg_size ?
-                       cpu_to_le32(xfer->seg_size) :
-                       cpu_to_le32(transfer_size);
-               transfer_size -=  xfer->seg_size;
-               for (cnt = 1; cnt < xfer->segs; cnt++) {
-                       xfer_hdr = &xfer->seg[cnt]->xfer_hdr;
-                       memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size);
-                       xfer_hdr->bTransferSegment = cnt;
-                       xfer_hdr->dwTransferLength =
-                               transfer_size > xfer->seg_size ?
-                                       cpu_to_le32(xfer->seg_size)
-                                       : cpu_to_le32(transfer_size);
-                       xfer->seg[cnt]->status = WA_SEG_READY;
-                       transfer_size -=  xfer->seg_size;
-               }
-       }
-       xfer_hdr->bTransferSegment |= 0x80;     /* this is the last segment */
-       result = 0;
-error_setup_segs:
-error_setup_sizes:
-       return result;
-}
-
-/*
- *
- *
- * rpipe->seg_lock is held!
- */
-static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer,
-                          struct wa_seg *seg, int *dto_done)
-{
-       int result;
-
-       /* default to done unless we encounter a multi-frame isoc segment. */
-       *dto_done = 1;
-
-       /*
-        * Take a ref for each segment urb so the xfer cannot disappear until
-        * all of the callbacks run.
-        */
-       wa_xfer_get(xfer);
-       /* submit the transfer request. */
-       seg->status = WA_SEG_SUBMITTED;
-       result = usb_submit_urb(&seg->tr_urb, GFP_ATOMIC);
-       if (result < 0) {
-               pr_err("%s: xfer %p#%u: REQ submit failed: %d\n",
-                      __func__, xfer, seg->index, result);
-               wa_xfer_put(xfer);
-               goto error_tr_submit;
-       }
-       /* submit the isoc packet descriptor if present. */
-       if (seg->isoc_pack_desc_urb) {
-               wa_xfer_get(xfer);
-               result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC);
-               seg->isoc_frame_index = 0;
-               if (result < 0) {
-                       pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n",
-                              __func__, xfer, seg->index, result);
-                       wa_xfer_put(xfer);
-                       goto error_iso_pack_desc_submit;
-               }
-       }
-       /* submit the out data if this is an out request. */
-       if (seg->dto_urb) {
-               struct wahc *wa = xfer->wa;
-               wa_xfer_get(xfer);
-               result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);
-               if (result < 0) {
-                       pr_err("%s: xfer %p#%u: DTO submit failed: %d\n",
-                              __func__, xfer, seg->index, result);
-                       wa_xfer_put(xfer);
-                       goto error_dto_submit;
-               }
-               /*
-                * If this segment contains more than one isoc frame, hold
-                * onto the dto resource until we send all frames.
-                * Only applies to non-Alereon devices.
-                */
-               if (((wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) == 0)
-                       && (seg->isoc_frame_count > 1))
-                       *dto_done = 0;
-       }
-       rpipe_avail_dec(rpipe);
-       return 0;
-
-error_dto_submit:
-       usb_unlink_urb(seg->isoc_pack_desc_urb);
-error_iso_pack_desc_submit:
-       usb_unlink_urb(&seg->tr_urb);
-error_tr_submit:
-       seg->status = WA_SEG_ERROR;
-       seg->result = result;
-       *dto_done = 1;
-       return result;
-}
-
-/*
- * Execute more queued request segments until the maximum concurrent allowed.
- * Return true if the DTO resource was acquired and released.
- *
- * The ugly unlock/lock sequence on the error path is needed as the
- * xfer->lock normally nests the seg_lock and not viceversa.
- */
-static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting)
-{
-       int result, dto_acquired = 0, dto_done = 0;
-       struct device *dev = &rpipe->wa->usb_iface->dev;
-       struct wa_seg *seg;
-       struct wa_xfer *xfer;
-       unsigned long flags;
-
-       *dto_waiting = 0;
-
-       spin_lock_irqsave(&rpipe->seg_lock, flags);
-       while (atomic_read(&rpipe->segs_available) > 0
-             && !list_empty(&rpipe->seg_list)
-             && (dto_acquired = __wa_dto_try_get(rpipe->wa))) {
-               seg = list_first_entry(&(rpipe->seg_list), struct wa_seg,
-                                list_node);
-               list_del(&seg->list_node);
-               xfer = seg->xfer;
-               /*
-                * Get a reference to the xfer in case the callbacks for the
-                * URBs submitted by __wa_seg_submit attempt to complete
-                * the xfer before this function completes.
-                */
-               wa_xfer_get(xfer);
-               result = __wa_seg_submit(rpipe, xfer, seg, &dto_done);
-               /* release the dto resource if this RPIPE is done with it. */
-               if (dto_done)
-                       __wa_dto_put(rpipe->wa);
-               dev_dbg(dev, "xfer %p ID %08X#%u submitted from delayed [%d segments available] %d\n",
-                       xfer, wa_xfer_id(xfer), seg->index,
-                       atomic_read(&rpipe->segs_available), result);
-               if (unlikely(result < 0)) {
-                       int done;
-
-                       spin_unlock_irqrestore(&rpipe->seg_lock, flags);
-                       spin_lock_irqsave(&xfer->lock, flags);
-                       __wa_xfer_abort(xfer);
-                       /*
-                        * This seg was marked as submitted when it was put on
-                        * the RPIPE seg_list.  Mark it done.
-                        */
-                       xfer->segs_done++;
-                       done = __wa_xfer_is_done(xfer);
-                       spin_unlock_irqrestore(&xfer->lock, flags);
-                       if (done)
-                               wa_xfer_completion(xfer);
-                       spin_lock_irqsave(&rpipe->seg_lock, flags);
-               }
-               wa_xfer_put(xfer);
-       }
-       /*
-        * Mark this RPIPE as waiting if dto was not acquired, there are
-        * delayed segs and no active transfers to wake us up later.
-        */
-       if (!dto_acquired && !list_empty(&rpipe->seg_list)
-               && (atomic_read(&rpipe->segs_available) ==
-                       le16_to_cpu(rpipe->descr.wRequests)))
-               *dto_waiting = 1;
-
-       spin_unlock_irqrestore(&rpipe->seg_lock, flags);
-
-       return dto_done;
-}
-
-static void wa_xfer_delayed_run(struct wa_rpipe *rpipe)
-{
-       int dto_waiting;
-       int dto_done = __wa_xfer_delayed_run(rpipe, &dto_waiting);
-
-       /*
-        * If this RPIPE is waiting on the DTO resource, add it to the tail of
-        * the waiting list.
-        * Otherwise, if the WA DTO resource was acquired and released by
-        *  __wa_xfer_delayed_run, another RPIPE may have attempted to acquire
-        * DTO and failed during that time.  Check the delayed list and process
-        * any waiters.  Start searching from the next RPIPE index.
-        */
-       if (dto_waiting)
-               wa_add_delayed_rpipe(rpipe->wa, rpipe);
-       else if (dto_done)
-               wa_check_for_delayed_rpipes(rpipe->wa);
-}
-
-/*
- *
- * xfer->lock is taken
- *
- * On failure submitting we just stop submitting and return error;
- * wa_urb_enqueue_b() will execute the completion path
- */
-static int __wa_xfer_submit(struct wa_xfer *xfer)
-{
-       int result, dto_acquired = 0, dto_done = 0, dto_waiting = 0;
-       struct wahc *wa = xfer->wa;
-       struct device *dev = &wa->usb_iface->dev;
-       unsigned cnt;
-       struct wa_seg *seg;
-       unsigned long flags;
-       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-       size_t maxrequests = le16_to_cpu(rpipe->descr.wRequests);
-       u8 available;
-       u8 empty;
-
-       spin_lock_irqsave(&wa->xfer_list_lock, flags);
-       list_add_tail(&xfer->list_node, &wa->xfer_list);
-       spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
-
-       BUG_ON(atomic_read(&rpipe->segs_available) > maxrequests);
-       result = 0;
-       spin_lock_irqsave(&rpipe->seg_lock, flags);
-       for (cnt = 0; cnt < xfer->segs; cnt++) {
-               int delay_seg = 1;
-
-               available = atomic_read(&rpipe->segs_available);
-               empty = list_empty(&rpipe->seg_list);
-               seg = xfer->seg[cnt];
-               if (available && empty) {
-                       /*
-                        * Only attempt to acquire DTO if we have a segment
-                        * to send.
-                        */
-                       dto_acquired = __wa_dto_try_get(rpipe->wa);
-                       if (dto_acquired) {
-                               delay_seg = 0;
-                               result = __wa_seg_submit(rpipe, xfer, seg,
-                                                       &dto_done);
-                               dev_dbg(dev, "xfer %p ID 0x%08X#%u: available %u empty %u submitted\n",
-                                       xfer, wa_xfer_id(xfer), cnt, available,
-                                       empty);
-                               if (dto_done)
-                                       __wa_dto_put(rpipe->wa);
-
-                               if (result < 0) {
-                                       __wa_xfer_abort(xfer);
-                                       goto error_seg_submit;
-                               }
-                       }
-               }
-
-               if (delay_seg) {
-                       dev_dbg(dev, "xfer %p ID 0x%08X#%u: available %u empty %u delayed\n",
-                               xfer, wa_xfer_id(xfer), cnt, available,  empty);
-                       seg->status = WA_SEG_DELAYED;
-                       list_add_tail(&seg->list_node, &rpipe->seg_list);
-               }
-               xfer->segs_submitted++;
-       }
-error_seg_submit:
-       /*
-        * Mark this RPIPE as waiting if dto was not acquired, there are
-        * delayed segs and no active transfers to wake us up later.
-        */
-       if (!dto_acquired && !list_empty(&rpipe->seg_list)
-               && (atomic_read(&rpipe->segs_available) ==
-                       le16_to_cpu(rpipe->descr.wRequests)))
-               dto_waiting = 1;
-       spin_unlock_irqrestore(&rpipe->seg_lock, flags);
-
-       if (dto_waiting)
-               wa_add_delayed_rpipe(rpipe->wa, rpipe);
-       else if (dto_done)
-               wa_check_for_delayed_rpipes(rpipe->wa);
-
-       return result;
-}
-
-/*
- * Second part of a URB/transfer enqueuement
- *
- * Assumes this comes from wa_urb_enqueue() [maybe through
- * wa_urb_enqueue_run()]. At this point:
- *
- * xfer->wa    filled and refcounted
- * xfer->ep    filled with rpipe refcounted if
- *              delayed == 0
- * xfer->urb   filled and refcounted (this is the case when called
- *              from wa_urb_enqueue() as we come from usb_submit_urb()
- *              and when called by wa_urb_enqueue_run(), as we took an
- *              extra ref dropped by _run() after we return).
- * xfer->gfp   filled
- *
- * If we fail at __wa_xfer_submit(), then we just check if we are done
- * and if so, we run the completion procedure. However, if we are not
- * yet done, we do nothing and wait for the completion handlers from
- * the submitted URBs or from the xfer-result path to kick in. If xfer
- * result never kicks in, the xfer will timeout from the USB code and
- * dequeue() will be called.
- */
-static int wa_urb_enqueue_b(struct wa_xfer *xfer)
-{
-       int result;
-       unsigned long flags;
-       struct urb *urb = xfer->urb;
-       struct wahc *wa = xfer->wa;
-       struct wusbhc *wusbhc = wa->wusb;
-       struct wusb_dev *wusb_dev;
-       unsigned done;
-
-       result = rpipe_get_by_ep(wa, xfer->ep, urb, xfer->gfp);
-       if (result < 0) {
-               pr_err("%s: error_rpipe_get\n", __func__);
-               goto error_rpipe_get;
-       }
-       result = -ENODEV;
-       /* FIXME: segmentation broken -- kills DWA */
-       mutex_lock(&wusbhc->mutex);             /* get a WUSB dev */
-       if (urb->dev == NULL) {
-               mutex_unlock(&wusbhc->mutex);
-               pr_err("%s: error usb dev gone\n", __func__);
-               goto error_dev_gone;
-       }
-       wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev);
-       if (wusb_dev == NULL) {
-               mutex_unlock(&wusbhc->mutex);
-               dev_err(&(urb->dev->dev), "%s: error wusb dev gone\n",
-                       __func__);
-               goto error_dev_gone;
-       }
-       mutex_unlock(&wusbhc->mutex);
-
-       spin_lock_irqsave(&xfer->lock, flags);
-       xfer->wusb_dev = wusb_dev;
-       result = urb->status;
-       if (urb->status != -EINPROGRESS) {
-               dev_err(&(urb->dev->dev), "%s: error_dequeued\n", __func__);
-               goto error_dequeued;
-       }
-
-       result = __wa_xfer_setup(xfer, urb);
-       if (result < 0) {
-               dev_err(&(urb->dev->dev), "%s: error_xfer_setup\n", __func__);
-               goto error_xfer_setup;
-       }
-       /*
-        * Get a xfer reference since __wa_xfer_submit starts asynchronous
-        * operations that may try to complete the xfer before this function
-        * exits.
-        */
-       wa_xfer_get(xfer);
-       result = __wa_xfer_submit(xfer);
-       if (result < 0) {
-               dev_err(&(urb->dev->dev), "%s: error_xfer_submit\n", __func__);
-               goto error_xfer_submit;
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       wa_xfer_put(xfer);
-       return 0;
-
-       /*
-        * this is basically wa_xfer_completion() broken up wa_xfer_giveback()
-        * does a wa_xfer_put() that will call wa_xfer_destroy() and undo
-        * setup().
-        */
-error_xfer_setup:
-error_dequeued:
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       /* FIXME: segmentation broken, kills DWA */
-       if (wusb_dev)
-               wusb_dev_put(wusb_dev);
-error_dev_gone:
-       rpipe_put(xfer->ep->hcpriv);
-error_rpipe_get:
-       xfer->result = result;
-       return result;
-
-error_xfer_submit:
-       done = __wa_xfer_is_done(xfer);
-       xfer->result = result;
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (done)
-               wa_xfer_completion(xfer);
-       wa_xfer_put(xfer);
-       /* return success since the completion routine will run. */
-       return 0;
-}
-
-/*
- * Execute the delayed transfers in the Wire Adapter @wa
- *
- * We need to be careful here, as dequeue() could be called in the
- * middle.  That's why we do the whole thing under the
- * wa->xfer_list_lock. If dequeue() jumps in, it first locks xfer->lock
- * and then checks the list -- so as we would be acquiring in inverse
- * order, we move the delayed list to a separate list while locked and then
- * submit them without the list lock held.
- */
-void wa_urb_enqueue_run(struct work_struct *ws)
-{
-       struct wahc *wa = container_of(ws, struct wahc, xfer_enqueue_work);
-       struct wa_xfer *xfer, *next;
-       struct urb *urb;
-       LIST_HEAD(tmp_list);
-
-       /* Create a copy of the wa->xfer_delayed_list while holding the lock */
-       spin_lock_irq(&wa->xfer_list_lock);
-       list_cut_position(&tmp_list, &wa->xfer_delayed_list,
-                       wa->xfer_delayed_list.prev);
-       spin_unlock_irq(&wa->xfer_list_lock);
-
-       /*
-        * enqueue from temp list without list lock held since wa_urb_enqueue_b
-        * can take xfer->lock as well as lock mutexes.
-        */
-       list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
-               list_del_init(&xfer->list_node);
-
-               urb = xfer->urb;
-               if (wa_urb_enqueue_b(xfer) < 0)
-                       wa_xfer_giveback(xfer);
-               usb_put_urb(urb);       /* taken when queuing */
-       }
-}
-EXPORT_SYMBOL_GPL(wa_urb_enqueue_run);
-
-/*
- * Process the errored transfers on the Wire Adapter outside of interrupt.
- */
-void wa_process_errored_transfers_run(struct work_struct *ws)
-{
-       struct wahc *wa = container_of(ws, struct wahc, xfer_error_work);
-       struct wa_xfer *xfer, *next;
-       LIST_HEAD(tmp_list);
-
-       pr_info("%s: Run delayed STALL processing.\n", __func__);
-
-       /* Create a copy of the wa->xfer_errored_list while holding the lock */
-       spin_lock_irq(&wa->xfer_list_lock);
-       list_cut_position(&tmp_list, &wa->xfer_errored_list,
-                       wa->xfer_errored_list.prev);
-       spin_unlock_irq(&wa->xfer_list_lock);
-
-       /*
-        * run rpipe_clear_feature_stalled from temp list without list lock
-        * held.
-        */
-       list_for_each_entry_safe(xfer, next, &tmp_list, list_node) {
-               struct usb_host_endpoint *ep;
-               unsigned long flags;
-               struct wa_rpipe *rpipe;
-
-               spin_lock_irqsave(&xfer->lock, flags);
-               ep = xfer->ep;
-               rpipe = ep->hcpriv;
-               spin_unlock_irqrestore(&xfer->lock, flags);
-
-               /* clear RPIPE feature stalled without holding a lock. */
-               rpipe_clear_feature_stalled(wa, ep);
-
-               /* complete the xfer. This removes it from the tmp list. */
-               wa_xfer_completion(xfer);
-
-               /* check for work. */
-               wa_xfer_delayed_run(rpipe);
-       }
-}
-EXPORT_SYMBOL_GPL(wa_process_errored_transfers_run);
-
-/*
- * Submit a transfer to the Wire Adapter in a delayed way
- *
- * The process of enqueuing involves possible sleeps() [see
- * enqueue_b(), for the rpipe_get() and the mutex_lock()]. If we are
- * in an atomic section, we defer the enqueue_b() call--else we call direct.
- *
- * @urb: We own a reference to it done by the HCI Linux USB stack that
- *       will be given up by calling usb_hcd_giveback_urb() or by
- *       returning error from this function -> ergo we don't have to
- *       refcount it.
- */
-int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,
-                  struct urb *urb, gfp_t gfp)
-{
-       int result;
-       struct device *dev = &wa->usb_iface->dev;
-       struct wa_xfer *xfer;
-       unsigned long my_flags;
-       unsigned cant_sleep = irqs_disabled() | in_atomic();
-
-       if ((urb->transfer_buffer == NULL)
-           && (urb->sg == NULL)
-           && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
-           && urb->transfer_buffer_length != 0) {
-               dev_err(dev, "BUG? urb %p: NULL xfer buffer & NODMA\n", urb);
-               dump_stack();
-       }
-
-       spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
-       result = usb_hcd_link_urb_to_ep(&(wa->wusb->usb_hcd), urb);
-       spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
-       if (result < 0)
-               goto error_link_urb;
-
-       result = -ENOMEM;
-       xfer = kzalloc(sizeof(*xfer), gfp);
-       if (xfer == NULL)
-               goto error_kmalloc;
-
-       result = -ENOENT;
-       if (urb->status != -EINPROGRESS)        /* cancelled */
-               goto error_dequeued;            /* before starting? */
-       wa_xfer_init(xfer);
-       xfer->wa = wa_get(wa);
-       xfer->urb = urb;
-       xfer->gfp = gfp;
-       xfer->ep = ep;
-       urb->hcpriv = xfer;
-
-       dev_dbg(dev, "xfer %p urb %p pipe 0x%02x [%d bytes] %s %s %s\n",
-               xfer, urb, urb->pipe, urb->transfer_buffer_length,
-               urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? "dma" : "nodma",
-               urb->pipe & USB_DIR_IN ? "inbound" : "outbound",
-               cant_sleep ? "deferred" : "inline");
-
-       if (cant_sleep) {
-               usb_get_urb(urb);
-               spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
-               list_add_tail(&xfer->list_node, &wa->xfer_delayed_list);
-               spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
-               queue_work(wusbd, &wa->xfer_enqueue_work);
-       } else {
-               result = wa_urb_enqueue_b(xfer);
-               if (result < 0) {
-                       /*
-                        * URB submit/enqueue failed.  Clean up, return an
-                        * error and do not run the callback.  This avoids
-                        * an infinite submit/complete loop.
-                        */
-                       dev_err(dev, "%s: URB enqueue failed: %d\n",
-                          __func__, result);
-                       wa_put(xfer->wa);
-                       wa_xfer_put(xfer);
-                       spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
-                       usb_hcd_unlink_urb_from_ep(&(wa->wusb->usb_hcd), urb);
-                       spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
-                       return result;
-               }
-       }
-       return 0;
-
-error_dequeued:
-       kfree(xfer);
-error_kmalloc:
-       spin_lock_irqsave(&wa->xfer_list_lock, my_flags);
-       usb_hcd_unlink_urb_from_ep(&(wa->wusb->usb_hcd), urb);
-       spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);
-error_link_urb:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wa_urb_enqueue);
-
-/*
- * Dequeue a URB and make sure uwb_hcd_giveback_urb() [completion
- * handler] is called.
- *
- * Until a transfer goes successfully through wa_urb_enqueue() it
- * needs to be dequeued with completion calling; when stuck in delayed
- * or before wa_xfer_setup() is called, we need to do completion.
- *
- *  not setup  If there is no hcpriv yet, that means that that enqueue
- *             still had no time to set the xfer up. Because
- *             urb->status should be other than -EINPROGRESS,
- *             enqueue() will catch that and bail out.
- *
- * If the transfer has gone through setup, we just need to clean it
- * up. If it has gone through submit(), we have to abort it [with an
- * asynch request] and then make sure we cancel each segment.
- *
- */
-int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
-{
-       unsigned long flags;
-       struct wa_xfer *xfer;
-       struct wa_seg *seg;
-       struct wa_rpipe *rpipe;
-       unsigned cnt, done = 0, xfer_abort_pending;
-       unsigned rpipe_ready = 0;
-       int result;
-
-       /* check if it is safe to unlink. */
-       spin_lock_irqsave(&wa->xfer_list_lock, flags);
-       result = usb_hcd_check_unlink_urb(&(wa->wusb->usb_hcd), urb, status);
-       if ((result == 0) && urb->hcpriv) {
-               /*
-                * Get a xfer ref to prevent a race with wa_xfer_giveback
-                * cleaning up the xfer while we are working with it.
-                */
-               wa_xfer_get(urb->hcpriv);
-       }
-       spin_unlock_irqrestore(&wa->xfer_list_lock, flags);
-       if (result)
-               return result;
-
-       xfer = urb->hcpriv;
-       if (xfer == NULL)
-               return -ENOENT;
-       spin_lock_irqsave(&xfer->lock, flags);
-       pr_debug("%s: DEQUEUE xfer id 0x%08X\n", __func__, wa_xfer_id(xfer));
-       rpipe = xfer->ep->hcpriv;
-       if (rpipe == NULL) {
-               pr_debug("%s: xfer %p id 0x%08X has no RPIPE.  %s",
-                       __func__, xfer, wa_xfer_id(xfer),
-                       "Probably already aborted.\n" );
-               result = -ENOENT;
-               goto out_unlock;
-       }
-       /*
-        * Check for done to avoid racing with wa_xfer_giveback and completing
-        * twice.
-        */
-       if (__wa_xfer_is_done(xfer)) {
-               pr_debug("%s: xfer %p id 0x%08X already done.\n", __func__,
-                       xfer, wa_xfer_id(xfer));
-               result = -ENOENT;
-               goto out_unlock;
-       }
-       /* Check the delayed list -> if there, release and complete */
-       spin_lock(&wa->xfer_list_lock);
-       if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
-               goto dequeue_delayed;
-       spin_unlock(&wa->xfer_list_lock);
-       if (xfer->seg == NULL)          /* still hasn't reached */
-               goto out_unlock;        /* setup(), enqueue_b() completes */
-       /* Ok, the xfer is in flight already, it's been setup and submitted.*/
-       xfer_abort_pending = __wa_xfer_abort(xfer) >= 0;
-       /*
-        * grab the rpipe->seg_lock here to prevent racing with
-        * __wa_xfer_delayed_run.
-        */
-       spin_lock(&rpipe->seg_lock);
-       for (cnt = 0; cnt < xfer->segs; cnt++) {
-               seg = xfer->seg[cnt];
-               pr_debug("%s: xfer id 0x%08X#%d status = %d\n",
-                       __func__, wa_xfer_id(xfer), cnt, seg->status);
-               switch (seg->status) {
-               case WA_SEG_NOTREADY:
-               case WA_SEG_READY:
-                       printk(KERN_ERR "xfer %p#%u: dequeue bad state %u\n",
-                              xfer, cnt, seg->status);
-                       WARN_ON(1);
-                       break;
-               case WA_SEG_DELAYED:
-                       /*
-                        * delete from rpipe delayed list.  If no segments on
-                        * this xfer have been submitted, __wa_xfer_is_done will
-                        * trigger a giveback below.  Otherwise, the submitted
-                        * segments will be completed in the DTI interrupt.
-                        */
-                       seg->status = WA_SEG_ABORTED;
-                       seg->result = -ENOENT;
-                       list_del(&seg->list_node);
-                       xfer->segs_done++;
-                       break;
-               case WA_SEG_DONE:
-               case WA_SEG_ERROR:
-               case WA_SEG_ABORTED:
-                       break;
-                       /*
-                        * The buf_in data for a segment in the
-                        * WA_SEG_DTI_PENDING state is actively being read.
-                        * Let wa_buf_in_cb handle it since it will be called
-                        * and will increment xfer->segs_done.  Cleaning up
-                        * here could cause wa_buf_in_cb to access the xfer
-                        * after it has been completed/freed.
-                        */
-               case WA_SEG_DTI_PENDING:
-                       break;
-                       /*
-                        * In the states below, the HWA device already knows
-                        * about the transfer.  If an abort request was sent,
-                        * allow the HWA to process it and wait for the
-                        * results.  Otherwise, the DTI state and seg completed
-                        * counts can get out of sync.
-                        */
-               case WA_SEG_SUBMITTED:
-               case WA_SEG_PENDING:
-                       /*
-                        * Check if the abort was successfully sent.  This could
-                        * be false if the HWA has been removed but we haven't
-                        * gotten the disconnect notification yet.
-                        */
-                       if (!xfer_abort_pending) {
-                               seg->status = WA_SEG_ABORTED;
-                               rpipe_ready = rpipe_avail_inc(rpipe);
-                               xfer->segs_done++;
-                       }
-                       break;
-               }
-       }
-       spin_unlock(&rpipe->seg_lock);
-       xfer->result = urb->status;     /* -ENOENT or -ECONNRESET */
-       done = __wa_xfer_is_done(xfer);
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (done)
-               wa_xfer_completion(xfer);
-       if (rpipe_ready)
-               wa_xfer_delayed_run(rpipe);
-       wa_xfer_put(xfer);
-       return result;
-
-out_unlock:
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       wa_xfer_put(xfer);
-       return result;
-
-dequeue_delayed:
-       list_del_init(&xfer->list_node);
-       spin_unlock(&wa->xfer_list_lock);
-       xfer->result = urb->status;
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       wa_xfer_giveback(xfer);
-       wa_xfer_put(xfer);
-       usb_put_urb(urb);               /* we got a ref in enqueue() */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(wa_urb_dequeue);
-
-/*
- * Translation from WA status codes (WUSB1.0 Table 8.15) to errno
- * codes
- *
- * Positive errno values are internal inconsistencies and should be
- * flagged louder. Negative are to be passed up to the user in the
- * normal way.
- *
- * @status: USB WA status code -- high two bits are stripped.
- */
-static int wa_xfer_status_to_errno(u8 status)
-{
-       int errno;
-       u8 real_status = status;
-       static int xlat[] = {
-               [WA_XFER_STATUS_SUCCESS] =              0,
-               [WA_XFER_STATUS_HALTED] =               -EPIPE,
-               [WA_XFER_STATUS_DATA_BUFFER_ERROR] =    -ENOBUFS,
-               [WA_XFER_STATUS_BABBLE] =               -EOVERFLOW,
-               [WA_XFER_RESERVED] =                    EINVAL,
-               [WA_XFER_STATUS_NOT_FOUND] =            0,
-               [WA_XFER_STATUS_INSUFFICIENT_RESOURCE] = -ENOMEM,
-               [WA_XFER_STATUS_TRANSACTION_ERROR] =    -EILSEQ,
-               [WA_XFER_STATUS_ABORTED] =              -ENOENT,
-               [WA_XFER_STATUS_RPIPE_NOT_READY] =      EINVAL,
-               [WA_XFER_INVALID_FORMAT] =              EINVAL,
-               [WA_XFER_UNEXPECTED_SEGMENT_NUMBER] =   EINVAL,
-               [WA_XFER_STATUS_RPIPE_TYPE_MISMATCH] =  EINVAL,
-       };
-       status &= 0x3f;
-
-       if (status == 0)
-               return 0;
-       if (status >= ARRAY_SIZE(xlat)) {
-               printk_ratelimited(KERN_ERR "%s(): BUG? "
-                              "Unknown WA transfer status 0x%02x\n",
-                              __func__, real_status);
-               return -EINVAL;
-       }
-       errno = xlat[status];
-       if (unlikely(errno > 0)) {
-               printk_ratelimited(KERN_ERR "%s(): BUG? "
-                              "Inconsistent WA status: 0x%02x\n",
-                              __func__, real_status);
-               errno = -errno;
-       }
-       return errno;
-}
-
-/*
- * If a last segment flag and/or a transfer result error is encountered,
- * no other segment transfer results will be returned from the device.
- * Mark the remaining submitted or pending xfers as completed so that
- * the xfer will complete cleanly.
- *
- * xfer->lock must be held
- *
- */
-static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer,
-               int starting_index, enum wa_seg_status status)
-{
-       int index;
-       struct wa_rpipe *rpipe = xfer->ep->hcpriv;
-
-       for (index = starting_index; index < xfer->segs_submitted; index++) {
-               struct wa_seg *current_seg = xfer->seg[index];
-
-               BUG_ON(current_seg == NULL);
-
-               switch (current_seg->status) {
-               case WA_SEG_SUBMITTED:
-               case WA_SEG_PENDING:
-               case WA_SEG_DTI_PENDING:
-                       rpipe_avail_inc(rpipe);
-               /*
-                * do not increment RPIPE avail for the WA_SEG_DELAYED case
-                * since it has not been submitted to the RPIPE.
-                */
-               /* fall through */
-               case WA_SEG_DELAYED:
-                       xfer->segs_done++;
-                       current_seg->status = status;
-                       break;
-               case WA_SEG_ABORTED:
-                       break;
-               default:
-                       WARN(1, "%s: xfer 0x%08X#%d. bad seg status = %d\n",
-                               __func__, wa_xfer_id(xfer), index,
-                               current_seg->status);
-                       break;
-               }
-       }
-}
-
-/* Populate the given urb based on the current isoc transfer state. */
-static int __wa_populate_buf_in_urb_isoc(struct wahc *wa,
-       struct urb *buf_in_urb, struct wa_xfer *xfer, struct wa_seg *seg)
-{
-       int urb_start_frame = seg->isoc_frame_index + seg->isoc_frame_offset;
-       int seg_index, total_len = 0, urb_frame_index = urb_start_frame;
-       struct usb_iso_packet_descriptor *iso_frame_desc =
-                                               xfer->urb->iso_frame_desc;
-       const int dti_packet_size = usb_endpoint_maxp(wa->dti_epd);
-       int next_frame_contiguous;
-       struct usb_iso_packet_descriptor *iso_frame;
-
-       BUG_ON(buf_in_urb->status == -EINPROGRESS);
-
-       /*
-        * If the current frame actual_length is contiguous with the next frame
-        * and actual_length is a multiple of the DTI endpoint max packet size,
-        * combine the current frame with the next frame in a single URB.  This
-        * reduces the number of URBs that must be submitted in that case.
-        */
-       seg_index = seg->isoc_frame_index;
-       do {
-               next_frame_contiguous = 0;
-
-               iso_frame = &iso_frame_desc[urb_frame_index];
-               total_len += iso_frame->actual_length;
-               ++urb_frame_index;
-               ++seg_index;
-
-               if (seg_index < seg->isoc_frame_count) {
-                       struct usb_iso_packet_descriptor *next_iso_frame;
-
-                       next_iso_frame = &iso_frame_desc[urb_frame_index];
-
-                       if ((iso_frame->offset + iso_frame->actual_length) ==
-                               next_iso_frame->offset)
-                               next_frame_contiguous = 1;
-               }
-       } while (next_frame_contiguous
-                       && ((iso_frame->actual_length % dti_packet_size) == 0));
-
-       /* this should always be 0 before a resubmit. */
-       buf_in_urb->num_mapped_sgs      = 0;
-       buf_in_urb->transfer_dma = xfer->urb->transfer_dma +
-               iso_frame_desc[urb_start_frame].offset;
-       buf_in_urb->transfer_buffer_length = total_len;
-       buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-       buf_in_urb->transfer_buffer = NULL;
-       buf_in_urb->sg = NULL;
-       buf_in_urb->num_sgs = 0;
-       buf_in_urb->context = seg;
-
-       /* return the number of frames included in this URB. */
-       return seg_index - seg->isoc_frame_index;
-}
-
-/* Populate the given urb based on the current transfer state. */
-static int wa_populate_buf_in_urb(struct urb *buf_in_urb, struct wa_xfer *xfer,
-       unsigned int seg_idx, unsigned int bytes_transferred)
-{
-       int result = 0;
-       struct wa_seg *seg = xfer->seg[seg_idx];
-
-       BUG_ON(buf_in_urb->status == -EINPROGRESS);
-       /* this should always be 0 before a resubmit. */
-       buf_in_urb->num_mapped_sgs      = 0;
-
-       if (xfer->is_dma) {
-               buf_in_urb->transfer_dma = xfer->urb->transfer_dma
-                       + (seg_idx * xfer->seg_size);
-               buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-               buf_in_urb->transfer_buffer = NULL;
-               buf_in_urb->sg = NULL;
-               buf_in_urb->num_sgs = 0;
-       } else {
-               /* do buffer or SG processing. */
-               buf_in_urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP;
-
-               if (xfer->urb->transfer_buffer) {
-                       buf_in_urb->transfer_buffer =
-                               xfer->urb->transfer_buffer
-                               + (seg_idx * xfer->seg_size);
-                       buf_in_urb->sg = NULL;
-                       buf_in_urb->num_sgs = 0;
-               } else {
-                       /* allocate an SG list to store seg_size bytes
-                               and copy the subset of the xfer->urb->sg
-                               that matches the buffer subset we are
-                               about to read. */
-                       buf_in_urb->sg = wa_xfer_create_subset_sg(
-                               xfer->urb->sg,
-                               seg_idx * xfer->seg_size,
-                               bytes_transferred,
-                               &(buf_in_urb->num_sgs));
-
-                       if (!(buf_in_urb->sg)) {
-                               buf_in_urb->num_sgs     = 0;
-                               result = -ENOMEM;
-                       }
-                       buf_in_urb->transfer_buffer = NULL;
-               }
-       }
-       buf_in_urb->transfer_buffer_length = bytes_transferred;
-       buf_in_urb->context = seg;
-
-       return result;
-}
-
-/*
- * Process a xfer result completion message
- *
- * inbound transfers: need to schedule a buf_in_urb read
- *
- * FIXME: this function needs to be broken up in parts
- */
-static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer,
-               struct wa_xfer_result *xfer_result)
-{
-       int result;
-       struct device *dev = &wa->usb_iface->dev;
-       unsigned long flags;
-       unsigned int seg_idx;
-       struct wa_seg *seg;
-       struct wa_rpipe *rpipe;
-       unsigned done = 0;
-       u8 usb_status;
-       unsigned rpipe_ready = 0;
-       unsigned bytes_transferred = le32_to_cpu(xfer_result->dwTransferLength);
-       struct urb *buf_in_urb = &(wa->buf_in_urbs[0]);
-
-       spin_lock_irqsave(&xfer->lock, flags);
-       seg_idx = xfer_result->bTransferSegment & 0x7f;
-       if (unlikely(seg_idx >= xfer->segs))
-               goto error_bad_seg;
-       seg = xfer->seg[seg_idx];
-       rpipe = xfer->ep->hcpriv;
-       usb_status = xfer_result->bTransferStatus;
-       dev_dbg(dev, "xfer %p ID 0x%08X#%u: bTransferStatus 0x%02x (seg status %u)\n",
-               xfer, wa_xfer_id(xfer), seg_idx, usb_status, seg->status);
-       if (seg->status == WA_SEG_ABORTED
-           || seg->status == WA_SEG_ERROR)     /* already handled */
-               goto segment_aborted;
-       if (seg->status == WA_SEG_SUBMITTED)    /* ops, got here */
-               seg->status = WA_SEG_PENDING;   /* before wa_seg{_dto}_cb() */
-       if (seg->status != WA_SEG_PENDING) {
-               if (printk_ratelimit())
-                       dev_err(dev, "xfer %p#%u: Bad segment state %u\n",
-                               xfer, seg_idx, seg->status);
-               seg->status = WA_SEG_PENDING;   /* workaround/"fix" it */
-       }
-       if (usb_status & 0x80) {
-               seg->result = wa_xfer_status_to_errno(usb_status);
-               dev_err(dev, "DTI: xfer %p 0x%08X:#%u failed (0x%02x)\n",
-                       xfer, xfer->id, seg->index, usb_status);
-               seg->status = ((usb_status & 0x7F) == WA_XFER_STATUS_ABORTED) ?
-                       WA_SEG_ABORTED : WA_SEG_ERROR;
-               goto error_complete;
-       }
-       /* FIXME: we ignore warnings, tally them for stats */
-       if (usb_status & 0x40)          /* Warning?... */
-               usb_status = 0;         /* ... pass */
-       /*
-        * If the last segment bit is set, complete the remaining segments.
-        * When the current segment is completed, either in wa_buf_in_cb for
-        * transfers with data or below for no data, the xfer will complete.
-        */
-       if (xfer_result->bTransferSegment & 0x80)
-               wa_complete_remaining_xfer_segs(xfer, seg->index + 1,
-                       WA_SEG_DONE);
-       if (usb_pipeisoc(xfer->urb->pipe)
-               && (le32_to_cpu(xfer_result->dwNumOfPackets) > 0)) {
-               /* set up WA state to read the isoc packet status next. */
-               wa->dti_isoc_xfer_in_progress = wa_xfer_id(xfer);
-               wa->dti_isoc_xfer_seg = seg_idx;
-               wa->dti_state = WA_DTI_ISOC_PACKET_STATUS_PENDING;
-       } else if (xfer->is_inbound && !usb_pipeisoc(xfer->urb->pipe)
-                       && (bytes_transferred > 0)) {
-               /* IN data phase: read to buffer */
-               seg->status = WA_SEG_DTI_PENDING;
-               result = wa_populate_buf_in_urb(buf_in_urb, xfer, seg_idx,
-                       bytes_transferred);
-               if (result < 0)
-                       goto error_buf_in_populate;
-               ++(wa->active_buf_in_urbs);
-               result = usb_submit_urb(buf_in_urb, GFP_ATOMIC);
-               if (result < 0) {
-                       --(wa->active_buf_in_urbs);
-                       goto error_submit_buf_in;
-               }
-       } else {
-               /* OUT data phase or no data, complete it -- */
-               seg->result = bytes_transferred;
-               rpipe_ready = rpipe_avail_inc(rpipe);
-               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (done)
-               wa_xfer_completion(xfer);
-       if (rpipe_ready)
-               wa_xfer_delayed_run(rpipe);
-       return;
-
-error_submit_buf_in:
-       if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
-               dev_err(dev, "DTI: URB max acceptable errors "
-                       "exceeded, resetting device\n");
-               wa_reset_all(wa);
-       }
-       if (printk_ratelimit())
-               dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n",
-                       xfer, seg_idx, result);
-       seg->result = result;
-       kfree(buf_in_urb->sg);
-       buf_in_urb->sg = NULL;
-error_buf_in_populate:
-       __wa_xfer_abort(xfer);
-       seg->status = WA_SEG_ERROR;
-error_complete:
-       xfer->segs_done++;
-       rpipe_ready = rpipe_avail_inc(rpipe);
-       wa_complete_remaining_xfer_segs(xfer, seg->index + 1, seg->status);
-       done = __wa_xfer_is_done(xfer);
-       /*
-        * queue work item to clear STALL for control endpoints.
-        * Otherwise, let endpoint_reset take care of it.
-        */
-       if (((usb_status & 0x3f) == WA_XFER_STATUS_HALTED) &&
-               usb_endpoint_xfer_control(&xfer->ep->desc) &&
-               done) {
-
-               dev_info(dev, "Control EP stall.  Queue delayed work.\n");
-               spin_lock(&wa->xfer_list_lock);
-               /* move xfer from xfer_list to xfer_errored_list. */
-               list_move_tail(&xfer->list_node, &wa->xfer_errored_list);
-               spin_unlock(&wa->xfer_list_lock);
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               queue_work(wusbd, &wa->xfer_error_work);
-       } else {
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (done)
-                       wa_xfer_completion(xfer);
-               if (rpipe_ready)
-                       wa_xfer_delayed_run(rpipe);
-       }
-
-       return;
-
-error_bad_seg:
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       wa_urb_dequeue(wa, xfer->urb, -ENOENT);
-       if (printk_ratelimit())
-               dev_err(dev, "xfer %p#%u: bad segment\n", xfer, seg_idx);
-       if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
-               dev_err(dev, "DTI: URB max acceptable errors "
-                       "exceeded, resetting device\n");
-               wa_reset_all(wa);
-       }
-       return;
-
-segment_aborted:
-       /* nothing to do, as the aborter did the completion */
-       spin_unlock_irqrestore(&xfer->lock, flags);
-}
-
-/*
- * Process a isochronous packet status message
- *
- * inbound transfers: need to schedule a buf_in_urb read
- */
-static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb)
-{
-       struct device *dev = &wa->usb_iface->dev;
-       struct wa_xfer_packet_status_hwaiso *packet_status;
-       struct wa_xfer_packet_status_len_hwaiso *status_array;
-       struct wa_xfer *xfer;
-       unsigned long flags;
-       struct wa_seg *seg;
-       struct wa_rpipe *rpipe;
-       unsigned done = 0, dti_busy = 0, data_frame_count = 0, seg_index;
-       unsigned first_frame_index = 0, rpipe_ready = 0;
-       size_t expected_size;
-
-       /* We have a xfer result buffer; check it */
-       dev_dbg(dev, "DTI: isoc packet status %d bytes at %p\n",
-               urb->actual_length, urb->transfer_buffer);
-       packet_status = (struct wa_xfer_packet_status_hwaiso *)(wa->dti_buf);
-       if (packet_status->bPacketType != WA_XFER_ISO_PACKET_STATUS) {
-               dev_err(dev, "DTI Error: isoc packet status--bad type 0x%02x\n",
-                       packet_status->bPacketType);
-               goto error_parse_buffer;
-       }
-       xfer = wa_xfer_get_by_id(wa, wa->dti_isoc_xfer_in_progress);
-       if (xfer == NULL) {
-               dev_err(dev, "DTI Error: isoc packet status--unknown xfer 0x%08x\n",
-                       wa->dti_isoc_xfer_in_progress);
-               goto error_parse_buffer;
-       }
-       spin_lock_irqsave(&xfer->lock, flags);
-       if (unlikely(wa->dti_isoc_xfer_seg >= xfer->segs))
-               goto error_bad_seg;
-       seg = xfer->seg[wa->dti_isoc_xfer_seg];
-       rpipe = xfer->ep->hcpriv;
-       expected_size = struct_size(packet_status, PacketStatus,
-                                   seg->isoc_frame_count);
-       if (urb->actual_length != expected_size) {
-               dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %zu needed)\n",
-                       urb->actual_length, expected_size);
-               goto error_bad_seg;
-       }
-       if (le16_to_cpu(packet_status->wLength) != expected_size) {
-               dev_err(dev, "DTI Error: isoc packet status--bad length %u\n",
-                       le16_to_cpu(packet_status->wLength));
-               goto error_bad_seg;
-       }
-       /* write isoc packet status and lengths back to the xfer urb. */
-       status_array = packet_status->PacketStatus;
-       xfer->urb->start_frame =
-               wa->wusb->usb_hcd.driver->get_frame_number(&wa->wusb->usb_hcd);
-       for (seg_index = 0; seg_index < seg->isoc_frame_count; ++seg_index) {
-               struct usb_iso_packet_descriptor *iso_frame_desc =
-                       xfer->urb->iso_frame_desc;
-               const int xfer_frame_index =
-                       seg->isoc_frame_offset + seg_index;
-
-               iso_frame_desc[xfer_frame_index].status =
-                       wa_xfer_status_to_errno(
-                       le16_to_cpu(status_array[seg_index].PacketStatus));
-               iso_frame_desc[xfer_frame_index].actual_length =
-                       le16_to_cpu(status_array[seg_index].PacketLength);
-               /* track the number of frames successfully transferred. */
-               if (iso_frame_desc[xfer_frame_index].actual_length > 0) {
-                       /* save the starting frame index for buf_in_urb. */
-                       if (!data_frame_count)
-                               first_frame_index = seg_index;
-                       ++data_frame_count;
-               }
-       }
-
-       if (xfer->is_inbound && data_frame_count) {
-               int result, total_frames_read = 0, urb_index = 0;
-               struct urb *buf_in_urb;
-
-               /* IN data phase: read to buffer */
-               seg->status = WA_SEG_DTI_PENDING;
-
-               /* start with the first frame with data. */
-               seg->isoc_frame_index = first_frame_index;
-               /* submit up to WA_MAX_BUF_IN_URBS read URBs. */
-               do {
-                       int urb_frame_index, urb_frame_count;
-                       struct usb_iso_packet_descriptor *iso_frame_desc;
-
-                       buf_in_urb = &(wa->buf_in_urbs[urb_index]);
-                       urb_frame_count = __wa_populate_buf_in_urb_isoc(wa,
-                               buf_in_urb, xfer, seg);
-                       /* advance frame index to start of next read URB. */
-                       seg->isoc_frame_index += urb_frame_count;
-                       total_frames_read += urb_frame_count;
-
-                       ++(wa->active_buf_in_urbs);
-                       result = usb_submit_urb(buf_in_urb, GFP_ATOMIC);
-
-                       /* skip 0-byte frames. */
-                       urb_frame_index =
-                               seg->isoc_frame_offset + seg->isoc_frame_index;
-                       iso_frame_desc =
-                               &(xfer->urb->iso_frame_desc[urb_frame_index]);
-                       while ((seg->isoc_frame_index <
-                                               seg->isoc_frame_count) &&
-                                (iso_frame_desc->actual_length == 0)) {
-                               ++(seg->isoc_frame_index);
-                               ++iso_frame_desc;
-                       }
-                       ++urb_index;
-
-               } while ((result == 0) && (urb_index < WA_MAX_BUF_IN_URBS)
-                               && (seg->isoc_frame_index <
-                                               seg->isoc_frame_count));
-
-               if (result < 0) {
-                       --(wa->active_buf_in_urbs);
-                       dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
-                               result);
-                       wa_reset_all(wa);
-               } else if (data_frame_count > total_frames_read)
-                       /* If we need to read more frames, set DTI busy. */
-                       dti_busy = 1;
-       } else {
-               /* OUT transfer or no more IN data, complete it -- */
-               rpipe_ready = rpipe_avail_inc(rpipe);
-               done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       if (dti_busy)
-               wa->dti_state = WA_DTI_BUF_IN_DATA_PENDING;
-       else
-               wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
-       if (done)
-               wa_xfer_completion(xfer);
-       if (rpipe_ready)
-               wa_xfer_delayed_run(rpipe);
-       wa_xfer_put(xfer);
-       return dti_busy;
-
-error_bad_seg:
-       spin_unlock_irqrestore(&xfer->lock, flags);
-       wa_xfer_put(xfer);
-error_parse_buffer:
-       return dti_busy;
-}
-
-/*
- * Callback for the IN data phase
- *
- * If successful transition state; otherwise, take a note of the
- * error, mark this segment done and try completion.
- *
- * Note we don't access until we are sure that the transfer hasn't
- * been cancelled (ECONNRESET, ENOENT), which could mean that
- * seg->xfer could be already gone.
- */
-static void wa_buf_in_cb(struct urb *urb)
-{
-       struct wa_seg *seg = urb->context;
-       struct wa_xfer *xfer = seg->xfer;
-       struct wahc *wa;
-       struct device *dev;
-       struct wa_rpipe *rpipe;
-       unsigned rpipe_ready = 0, isoc_data_frame_count = 0;
-       unsigned long flags;
-       int resubmit_dti = 0, active_buf_in_urbs;
-       u8 done = 0;
-
-       /* free the sg if it was used. */
-       kfree(urb->sg);
-       urb->sg = NULL;
-
-       spin_lock_irqsave(&xfer->lock, flags);
-       wa = xfer->wa;
-       dev = &wa->usb_iface->dev;
-       --(wa->active_buf_in_urbs);
-       active_buf_in_urbs = wa->active_buf_in_urbs;
-       rpipe = xfer->ep->hcpriv;
-
-       if (usb_pipeisoc(xfer->urb->pipe)) {
-               struct usb_iso_packet_descriptor *iso_frame_desc =
-                       xfer->urb->iso_frame_desc;
-               int     seg_index;
-
-               /*
-                * Find the next isoc frame with data and count how many
-                * frames with data remain.
-                */
-               seg_index = seg->isoc_frame_index;
-               while (seg_index < seg->isoc_frame_count) {
-                       const int urb_frame_index =
-                               seg->isoc_frame_offset + seg_index;
-
-                       if (iso_frame_desc[urb_frame_index].actual_length > 0) {
-                               /* save the index of the next frame with data */
-                               if (!isoc_data_frame_count)
-                                       seg->isoc_frame_index = seg_index;
-                               ++isoc_data_frame_count;
-                       }
-                       ++seg_index;
-               }
-       }
-       spin_unlock_irqrestore(&xfer->lock, flags);
-
-       switch (urb->status) {
-       case 0:
-               spin_lock_irqsave(&xfer->lock, flags);
-
-               seg->result += urb->actual_length;
-               if (isoc_data_frame_count > 0) {
-                       int result, urb_frame_count;
-
-                       /* submit a read URB for the next frame with data. */
-                       urb_frame_count = __wa_populate_buf_in_urb_isoc(wa, urb,
-                                xfer, seg);
-                       /* advance index to start of next read URB. */
-                       seg->isoc_frame_index += urb_frame_count;
-                       ++(wa->active_buf_in_urbs);
-                       result = usb_submit_urb(urb, GFP_ATOMIC);
-                       if (result < 0) {
-                               --(wa->active_buf_in_urbs);
-                               dev_err(dev, "DTI Error: Could not submit buf in URB (%d)",
-                                       result);
-                               wa_reset_all(wa);
-                       }
-                       /*
-                        * If we are in this callback and
-                        * isoc_data_frame_count > 0, it means that the dti_urb
-                        * submission was delayed in wa_dti_cb.  Once
-                        * we submit the last buf_in_urb, we can submit the
-                        * delayed dti_urb.
-                        */
-                         resubmit_dti = (isoc_data_frame_count ==
-                                                       urb_frame_count);
-               } else if (active_buf_in_urbs == 0) {
-                       dev_dbg(dev,
-                               "xfer %p 0x%08X#%u: data in done (%zu bytes)\n",
-                               xfer, wa_xfer_id(xfer), seg->index,
-                               seg->result);
-                       rpipe_ready = rpipe_avail_inc(rpipe);
-                       done = __wa_xfer_mark_seg_as_done(xfer, seg,
-                                       WA_SEG_DONE);
-               }
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (done)
-                       wa_xfer_completion(xfer);
-               if (rpipe_ready)
-                       wa_xfer_delayed_run(rpipe);
-               break;
-       case -ECONNRESET:       /* URB unlinked; no need to do anything */
-       case -ENOENT:           /* as it was done by the who unlinked us */
-               break;
-       default:                /* Other errors ... */
-               /*
-                * Error on data buf read.  Only resubmit DTI if it hasn't
-                * already been done by previously hitting this error or by a
-                * successful completion of the previous buf_in_urb.
-                */
-               resubmit_dti = wa->dti_state != WA_DTI_TRANSFER_RESULT_PENDING;
-               spin_lock_irqsave(&xfer->lock, flags);
-               if (printk_ratelimit())
-                       dev_err(dev, "xfer %p 0x%08X#%u: data in error %d\n",
-                               xfer, wa_xfer_id(xfer), seg->index,
-                               urb->status);
-               if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)){
-                       dev_err(dev, "DTO: URB max acceptable errors "
-                               "exceeded, resetting device\n");
-                       wa_reset_all(wa);
-               }
-               seg->result = urb->status;
-               rpipe_ready = rpipe_avail_inc(rpipe);
-               if (active_buf_in_urbs == 0)
-                       done = __wa_xfer_mark_seg_as_done(xfer, seg,
-                               WA_SEG_ERROR);
-               else
-                       __wa_xfer_abort(xfer);
-               spin_unlock_irqrestore(&xfer->lock, flags);
-               if (done)
-                       wa_xfer_completion(xfer);
-               if (rpipe_ready)
-                       wa_xfer_delayed_run(rpipe);
-       }
-
-       if (resubmit_dti) {
-               int result;
-
-               wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;
-
-               result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
-               if (result < 0) {
-                       dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n",
-                               result);
-                       wa_reset_all(wa);
-               }
-       }
-}
-
-/*
- * Handle an incoming transfer result buffer
- *
- * Given a transfer result buffer, it completes the transfer (possibly
- * scheduling and buffer in read) and then resubmits the DTI URB for a
- * new transfer result read.
- *
- *
- * The xfer_result DTI URB state machine
- *
- * States: OFF | RXR (Read-Xfer-Result) | RBI (Read-Buffer-In)
- *
- * We start in OFF mode, the first xfer_result notification [through
- * wa_handle_notif_xfer()] moves us to RXR by posting the DTI-URB to
- * read.
- *
- * We receive a buffer -- if it is not a xfer_result, we complain and
- * repost the DTI-URB. If it is a xfer_result then do the xfer seg
- * request accounting. If it is an IN segment, we move to RBI and post
- * a BUF-IN-URB to the right buffer. The BUF-IN-URB callback will
- * repost the DTI-URB and move to RXR state. if there was no IN
- * segment, it will repost the DTI-URB.
- *
- * We go back to OFF when we detect a ENOENT or ESHUTDOWN (or too many
- * errors) in the URBs.
- */
-static void wa_dti_cb(struct urb *urb)
-{
-       int result, dti_busy = 0;
-       struct wahc *wa = urb->context;
-       struct device *dev = &wa->usb_iface->dev;
-       u32 xfer_id;
-       u8 usb_status;
-
-       BUG_ON(wa->dti_urb != urb);
-       switch (wa->dti_urb->status) {
-       case 0:
-               if (wa->dti_state == WA_DTI_TRANSFER_RESULT_PENDING) {
-                       struct wa_xfer_result *xfer_result;
-                       struct wa_xfer *xfer;
-
-                       /* We have a xfer result buffer; check it */
-                       dev_dbg(dev, "DTI: xfer result %d bytes at %p\n",
-                               urb->actual_length, urb->transfer_buffer);
-                       if (urb->actual_length != sizeof(*xfer_result)) {
-                               dev_err(dev, "DTI Error: xfer result--bad size xfer result (%d bytes vs %zu needed)\n",
-                                       urb->actual_length,
-                                       sizeof(*xfer_result));
-                               break;
-                       }
-                       xfer_result = (struct wa_xfer_result *)(wa->dti_buf);
-                       if (xfer_result->hdr.bLength != sizeof(*xfer_result)) {
-                               dev_err(dev, "DTI Error: xfer result--bad header length %u\n",
-                                       xfer_result->hdr.bLength);
-                               break;
-                       }
-                       if (xfer_result->hdr.bNotifyType != WA_XFER_RESULT) {
-                               dev_err(dev, "DTI Error: xfer result--bad header type 0x%02x\n",
-                                       xfer_result->hdr.bNotifyType);
-                               break;
-                       }
-                       xfer_id = le32_to_cpu(xfer_result->dwTransferID);
-                       usb_status = xfer_result->bTransferStatus & 0x3f;
-                       if (usb_status == WA_XFER_STATUS_NOT_FOUND) {
-                               /* taken care of already */
-                               dev_dbg(dev, "%s: xfer 0x%08X#%u not found.\n",
-                                       __func__, xfer_id,
-                                       xfer_result->bTransferSegment & 0x7f);
-                               break;
-                       }
-                       xfer = wa_xfer_get_by_id(wa, xfer_id);
-                       if (xfer == NULL) {
-                               /* FIXME: transaction not found. */
-                               dev_err(dev, "DTI Error: xfer result--unknown xfer 0x%08x (status 0x%02x)\n",
-                                       xfer_id, usb_status);
-                               break;
-                       }
-                       wa_xfer_result_chew(wa, xfer, xfer_result);
-                       wa_xfer_put(xfer);
-               } else if (wa->dti_state == WA_DTI_ISOC_PACKET_STATUS_PENDING) {
-                       dti_busy = wa_process_iso_packet_status(wa, urb);
-               } else {
-                       dev_err(dev, "DTI Error: unexpected EP state = %d\n",
-                               wa->dti_state);
-               }
-               break;
-       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
-       case -ESHUTDOWN:        /* going away! */
-               dev_dbg(dev, "DTI: going down! %d\n", urb->status);
-               goto out;
-       default:
-               /* Unknown error */
-               if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME)) {
-                       dev_err(dev, "DTI: URB max acceptable errors "
-                               "exceeded, resetting device\n");
-                       wa_reset_all(wa);
-                       goto out;
-               }
-               if (printk_ratelimit())
-                       dev_err(dev, "DTI: URB error %d\n", urb->status);
-               break;
-       }
-
-       /* Resubmit the DTI URB if we are not busy processing isoc in frames. */
-       if (!dti_busy) {
-               result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC);
-               if (result < 0) {
-                       dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n",
-                               result);
-                       wa_reset_all(wa);
-               }
-       }
-out:
-       return;
-}
-
-/*
- * Initialize the DTI URB for reading transfer result notifications and also
- * the buffer-in URB, for reading buffers. Then we just submit the DTI URB.
- */
-int wa_dti_start(struct wahc *wa)
-{
-       const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
-       struct device *dev = &wa->usb_iface->dev;
-       int result = -ENOMEM, index;
-
-       if (wa->dti_urb != NULL)        /* DTI URB already started */
-               goto out;
-
-       wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (wa->dti_urb == NULL)
-               goto error_dti_urb_alloc;
-       usb_fill_bulk_urb(
-               wa->dti_urb, wa->usb_dev,
-               usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress),
-               wa->dti_buf, wa->dti_buf_size,
-               wa_dti_cb, wa);
-
-       /* init the buf in URBs */
-       for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index) {
-               usb_fill_bulk_urb(
-                       &(wa->buf_in_urbs[index]), wa->usb_dev,
-                       usb_rcvbulkpipe(wa->usb_dev,
-                               0x80 | dti_epd->bEndpointAddress),
-                       NULL, 0, wa_buf_in_cb, wa);
-       }
-       result = usb_submit_urb(wa->dti_urb, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "DTI Error: Could not submit DTI URB (%d) resetting\n",
-                       result);
-               goto error_dti_urb_submit;
-       }
-out:
-       return 0;
-
-error_dti_urb_submit:
-       usb_put_urb(wa->dti_urb);
-       wa->dti_urb = NULL;
-error_dti_urb_alloc:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wa_dti_start);
-/*
- * Transfer complete notification
- *
- * Called from the notif.c code. We get a notification on EP2 saying
- * that some endpoint has some transfer result data available. We are
- * about to read it.
- *
- * To speed up things, we always have a URB reading the DTI URB; we
- * don't really set it up and start it until the first xfer complete
- * notification arrives, which is what we do here.
- *
- * Follow up in wa_dti_cb(), as that's where the whole state
- * machine starts.
- *
- * @wa shall be referenced
- */
-void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)
-{
-       struct device *dev = &wa->usb_iface->dev;
-       struct wa_notif_xfer *notif_xfer;
-       const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd;
-
-       notif_xfer = container_of(notif_hdr, struct wa_notif_xfer, hdr);
-       BUG_ON(notif_hdr->bNotifyType != WA_NOTIF_TRANSFER);
-
-       if ((0x80 | notif_xfer->bEndpoint) != dti_epd->bEndpointAddress) {
-               /* FIXME: hardcoded limitation, adapt */
-               dev_err(dev, "BUG: DTI ep is %u, not %u (hack me)\n",
-                       notif_xfer->bEndpoint, dti_epd->bEndpointAddress);
-               goto error;
-       }
-
-       /* attempt to start the DTI ep processing. */
-       if (wa_dti_start(wa) < 0)
-               goto error;
-
-       return;
-
-error:
-       wa_reset_all(wa);
-}
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c
deleted file mode 100644 (file)
index d0b404d..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Host Controller
- * sysfs glue, wusbcore module support and life cycle management
- *
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Creation/destruction of wusbhc is split in two parts; that that
- * doesn't require the HCD to be added (wusbhc_{create,destroy}) and
- * the one that requires (phase B, wusbhc_b_{create,destroy}).
- *
- * This is so because usb_add_hcd() will start the HC, and thus, all
- * the HC specific stuff has to be already initialized (like sysfs
- * thingies).
- */
-#include <linux/device.h>
-#include <linux/module.h>
-#include "wusbhc.h"
-
-/**
- * Extract the wusbhc that corresponds to a USB Host Controller class device
- *
- * WARNING! Apply only if @dev is that of a
- *          wusbhc.usb_hcd.self->class_dev; otherwise, you loose.
- */
-static struct wusbhc *usbhc_dev_to_wusbhc(struct device *dev)
-{
-       struct usb_bus *usb_bus = dev_get_drvdata(dev);
-       struct usb_hcd *usb_hcd = bus_to_hcd(usb_bus);
-       return usb_hcd_to_wusbhc(usb_hcd);
-}
-
-/*
- * Show & store the current WUSB trust timeout
- *
- * We don't do locking--it is an 'atomic' value.
- *
- * The units that we store/show are always MILLISECONDS. However, the
- * value of trust_timeout is jiffies.
- */
-static ssize_t wusb_trust_timeout_show(struct device *dev,
-                                       struct device_attribute *attr,
-                                       char *buf)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-
-       return scnprintf(buf, PAGE_SIZE, "%u\n", wusbhc->trust_timeout);
-}
-
-static ssize_t wusb_trust_timeout_store(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t size)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       ssize_t result = -ENOSYS;
-       unsigned trust_timeout;
-
-       result = sscanf(buf, "%u", &trust_timeout);
-       if (result != 1) {
-               result = -EINVAL;
-               goto out;
-       }
-       wusbhc->trust_timeout = min_t(unsigned, trust_timeout, 500);
-       cancel_delayed_work(&wusbhc->keep_alive_timer);
-       flush_workqueue(wusbd);
-       queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
-                          msecs_to_jiffies(wusbhc->trust_timeout / 2));
-out:
-       return result < 0 ? result : size;
-}
-static DEVICE_ATTR_RW(wusb_trust_timeout);
-
-/*
- * Show the current WUSB CHID.
- */
-static ssize_t wusb_chid_show(struct device *dev,
-                             struct device_attribute *attr, char *buf)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       const struct wusb_ckhdid *chid;
-
-       if (wusbhc->wuie_host_info != NULL)
-               chid = &wusbhc->wuie_host_info->CHID;
-       else
-               chid = &wusb_ckhdid_zero;
-
-       return sprintf(buf, "%16ph\n", chid->data);
-}
-
-/*
- * Store a new CHID.
- *
- * - Write an all zeros CHID and it will stop the controller
- * - Write a non-zero CHID and it will start it.
- *
- * See wusbhc_chid_set() for more info.
- */
-static ssize_t wusb_chid_store(struct device *dev,
-                              struct device_attribute *attr,
-                              const char *buf, size_t size)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       struct wusb_ckhdid chid;
-       ssize_t result;
-
-       result = sscanf(buf,
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx "
-                       "%02hhx %02hhx %02hhx %02hhx\n",
-                       &chid.data[0] , &chid.data[1] ,
-                       &chid.data[2] , &chid.data[3] ,
-                       &chid.data[4] , &chid.data[5] ,
-                       &chid.data[6] , &chid.data[7] ,
-                       &chid.data[8] , &chid.data[9] ,
-                       &chid.data[10], &chid.data[11],
-                       &chid.data[12], &chid.data[13],
-                       &chid.data[14], &chid.data[15]);
-       if (result != 16) {
-               dev_err(dev, "Unrecognized CHID (need 16 8-bit hex digits): "
-                       "%d\n", (int)result);
-               return -EINVAL;
-       }
-       result = wusbhc_chid_set(wusbhc, &chid);
-       return result < 0 ? result : size;
-}
-static DEVICE_ATTR_RW(wusb_chid);
-
-
-static ssize_t wusb_phy_rate_show(struct device *dev,
-                                 struct device_attribute *attr,
-                                 char *buf)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-
-       return sprintf(buf, "%d\n", wusbhc->phy_rate);
-}
-
-static ssize_t wusb_phy_rate_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t size)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       uint8_t phy_rate;
-       ssize_t result;
-
-       result = sscanf(buf, "%hhu", &phy_rate);
-       if (result != 1)
-               return -EINVAL;
-       if (phy_rate >= UWB_PHY_RATE_INVALID)
-               return -EINVAL;
-
-       wusbhc->phy_rate = phy_rate;
-       return size;
-}
-static DEVICE_ATTR_RW(wusb_phy_rate);
-
-static ssize_t wusb_dnts_show(struct device *dev,
-                                 struct device_attribute *attr,
-                                 char *buf)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-
-       return sprintf(buf, "num slots: %d\ninterval: %dms\n",
-                       wusbhc->dnts_num_slots, wusbhc->dnts_interval);
-}
-
-static ssize_t wusb_dnts_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t size)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       uint8_t num_slots, interval;
-       ssize_t result;
-
-       result = sscanf(buf, "%hhu %hhu", &num_slots, &interval);
-
-       if (result != 2)
-               return -EINVAL;
-
-       wusbhc->dnts_num_slots = num_slots;
-       wusbhc->dnts_interval = interval;
-
-       return size;
-}
-static DEVICE_ATTR_RW(wusb_dnts);
-
-static ssize_t wusb_retry_count_show(struct device *dev,
-                                 struct device_attribute *attr,
-                                 char *buf)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-
-       return sprintf(buf, "%d\n", wusbhc->retry_count);
-}
-
-static ssize_t wusb_retry_count_store(struct device *dev,
-                                  struct device_attribute *attr,
-                                  const char *buf, size_t size)
-{
-       struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
-       uint8_t retry_count;
-       ssize_t result;
-
-       result = sscanf(buf, "%hhu", &retry_count);
-
-       if (result != 1)
-               return -EINVAL;
-
-       wusbhc->retry_count = max_t(uint8_t, retry_count,
-                                       WUSB_RETRY_COUNT_MAX);
-
-       return size;
-}
-static DEVICE_ATTR_RW(wusb_retry_count);
-
-/* Group all the WUSBHC attributes */
-static struct attribute *wusbhc_attrs[] = {
-               &dev_attr_wusb_trust_timeout.attr,
-               &dev_attr_wusb_chid.attr,
-               &dev_attr_wusb_phy_rate.attr,
-               &dev_attr_wusb_dnts.attr,
-               &dev_attr_wusb_retry_count.attr,
-               NULL,
-};
-
-static const struct attribute_group wusbhc_attr_group = {
-       .name = NULL,   /* we want them in the same directory */
-       .attrs = wusbhc_attrs,
-};
-
-/*
- * Create a wusbhc instance
- *
- * NOTEs:
- *
- *  - assumes *wusbhc has been zeroed and wusbhc->usb_hcd has been
- *    initialized but not added.
- *
- *  - fill out ports_max, mmcies_max and mmcie_{add,rm} before calling.
- *
- *  - fill out wusbhc->uwb_rc and refcount it before calling
- *  - fill out the wusbhc->sec_modes array
- */
-int wusbhc_create(struct wusbhc *wusbhc)
-{
-       int result = 0;
-
-       /* set defaults.  These can be overwritten using sysfs attributes. */
-       wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS;
-       wusbhc->phy_rate = UWB_PHY_RATE_INVALID - 1;
-       wusbhc->dnts_num_slots = 4;
-       wusbhc->dnts_interval = 2;
-       wusbhc->retry_count = WUSB_RETRY_COUNT_INFINITE;
-
-       mutex_init(&wusbhc->mutex);
-       result = wusbhc_mmcie_create(wusbhc);
-       if (result < 0)
-               goto error_mmcie_create;
-       result = wusbhc_devconnect_create(wusbhc);
-       if (result < 0)
-               goto error_devconnect_create;
-       result = wusbhc_rh_create(wusbhc);
-       if (result < 0)
-               goto error_rh_create;
-       result = wusbhc_sec_create(wusbhc);
-       if (result < 0)
-               goto error_sec_create;
-       return 0;
-
-error_sec_create:
-       wusbhc_rh_destroy(wusbhc);
-error_rh_create:
-       wusbhc_devconnect_destroy(wusbhc);
-error_devconnect_create:
-       wusbhc_mmcie_destroy(wusbhc);
-error_mmcie_create:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wusbhc_create);
-
-static inline struct kobject *wusbhc_kobj(struct wusbhc *wusbhc)
-{
-       return &wusbhc->usb_hcd.self.controller->kobj;
-}
-
-/*
- * Phase B of a wusbhc instance creation
- *
- * Creates fields that depend on wusbhc->usb_hcd having been
- * added. This is where we create the sysfs files in
- * /sys/class/usb_host/usb_hostX/.
- *
- * NOTE: Assumes wusbhc->usb_hcd has been already added by the upper
- *       layer (hwahc or whci)
- */
-int wusbhc_b_create(struct wusbhc *wusbhc)
-{
-       int result = 0;
-       struct device *dev = wusbhc->usb_hcd.self.controller;
-
-       result = sysfs_create_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
-       if (result < 0) {
-               dev_err(dev, "Cannot register WUSBHC attributes: %d\n",
-                       result);
-               goto error_create_attr_group;
-       }
-
-       return 0;
-error_create_attr_group:
-       return result;
-}
-EXPORT_SYMBOL_GPL(wusbhc_b_create);
-
-void wusbhc_b_destroy(struct wusbhc *wusbhc)
-{
-       wusbhc_pal_unregister(wusbhc);
-       sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
-}
-EXPORT_SYMBOL_GPL(wusbhc_b_destroy);
-
-void wusbhc_destroy(struct wusbhc *wusbhc)
-{
-       wusbhc_sec_destroy(wusbhc);
-       wusbhc_rh_destroy(wusbhc);
-       wusbhc_devconnect_destroy(wusbhc);
-       wusbhc_mmcie_destroy(wusbhc);
-}
-EXPORT_SYMBOL_GPL(wusbhc_destroy);
-
-struct workqueue_struct *wusbd;
-EXPORT_SYMBOL_GPL(wusbd);
-
-/*
- * WUSB Cluster ID allocation map
- *
- * Each WUSB bus in a channel is identified with a Cluster Id in the
- * unauth address pace (WUSB1.0[4.3]). We take the range 0xe0 to 0xff
- * (that's space for 31 WUSB controllers, as 0xff can't be taken). We
- * start taking from 0xff, 0xfe, 0xfd... (hence the += or -= 0xff).
- *
- * For each one we taken, we pin it in the bitap
- */
-#define CLUSTER_IDS 32
-static DECLARE_BITMAP(wusb_cluster_id_table, CLUSTER_IDS);
-static DEFINE_SPINLOCK(wusb_cluster_ids_lock);
-
-/*
- * Get a WUSB Cluster ID
- *
- * Need to release with wusb_cluster_id_put() when done w/ it.
- */
-/* FIXME: coordinate with the choose_addres() from the USB stack */
-/* we want to leave the top of the 128 range for cluster addresses and
- * the bottom for device addresses (as we map them one on one with
- * ports). */
-u8 wusb_cluster_id_get(void)
-{
-       u8 id;
-       spin_lock(&wusb_cluster_ids_lock);
-       id = find_first_zero_bit(wusb_cluster_id_table, CLUSTER_IDS);
-       if (id >= CLUSTER_IDS) {
-               id = 0;
-               goto out;
-       }
-       set_bit(id, wusb_cluster_id_table);
-       id = (u8) 0xff - id;
-out:
-       spin_unlock(&wusb_cluster_ids_lock);
-       return id;
-
-}
-EXPORT_SYMBOL_GPL(wusb_cluster_id_get);
-
-/*
- * Release a WUSB Cluster ID
- *
- * Obtained it with wusb_cluster_id_get()
- */
-void wusb_cluster_id_put(u8 id)
-{
-       id = 0xff - id;
-       BUG_ON(id >= CLUSTER_IDS);
-       spin_lock(&wusb_cluster_ids_lock);
-       WARN_ON(!test_bit(id, wusb_cluster_id_table));
-       clear_bit(id, wusb_cluster_id_table);
-       spin_unlock(&wusb_cluster_ids_lock);
-}
-EXPORT_SYMBOL_GPL(wusb_cluster_id_put);
-
-/**
- * wusbhc_giveback_urb - return an URB to the USB core
- * @wusbhc: the host controller the URB is from.
- * @urb:    the URB.
- * @status: the URB's status.
- *
- * Return an URB to the USB core doing some additional WUSB specific
- * processing.
- *
- *  - After a successful transfer, update the trust timeout timestamp
- *    for the WUSB device.
- *
- *  - [WUSB] sections 4.13 and 7.5.1 specify the stop retransmission
- *    condition for the WCONNECTACK_IE is that the host has observed
- *    the associated device responding to a control transfer.
- */
-void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status)
-{
-       struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc,
-                                       urb->dev);
-
-       if (status == 0 && wusb_dev) {
-               wusb_dev->entry_ts = jiffies;
-
-               /* wusbhc_devconnect_acked() can't be called from
-                  atomic context so defer it to a work queue. */
-               if (!list_empty(&wusb_dev->cack_node))
-                       queue_work(wusbd, &wusb_dev->devconnect_acked_work);
-               else
-                       wusb_dev_put(wusb_dev);
-       }
-
-       usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status);
-}
-EXPORT_SYMBOL_GPL(wusbhc_giveback_urb);
-
-/**
- * wusbhc_reset_all - reset the HC hardware
- * @wusbhc: the host controller to reset.
- *
- * Request a full hardware reset of the chip.  This will also reset
- * the radio controller and any other PALs.
- */
-void wusbhc_reset_all(struct wusbhc *wusbhc)
-{
-       if (wusbhc->uwb_rc)
-               uwb_rc_reset_all(wusbhc->uwb_rc);
-}
-EXPORT_SYMBOL_GPL(wusbhc_reset_all);
-
-static struct notifier_block wusb_usb_notifier = {
-       .notifier_call = wusb_usb_ncb,
-       .priority = INT_MAX     /* Need to be called first of all */
-};
-
-static int __init wusbcore_init(void)
-{
-       int result;
-       result = wusb_crypto_init();
-       if (result < 0)
-               goto error_crypto_init;
-       /* WQ is singlethread because we need to serialize notifications */
-       wusbd = create_singlethread_workqueue("wusbd");
-       if (wusbd == NULL) {
-               result = -ENOMEM;
-               printk(KERN_ERR "WUSB-core: Cannot create wusbd workqueue\n");
-               goto error_wusbd_create;
-       }
-       usb_register_notify(&wusb_usb_notifier);
-       bitmap_zero(wusb_cluster_id_table, CLUSTER_IDS);
-       set_bit(0, wusb_cluster_id_table);      /* reserve Cluster ID 0xff */
-       return 0;
-
-error_wusbd_create:
-       wusb_crypto_exit();
-error_crypto_init:
-       return result;
-
-}
-module_init(wusbcore_init);
-
-static void __exit wusbcore_exit(void)
-{
-       clear_bit(0, wusb_cluster_id_table);
-       if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) {
-               printk(KERN_ERR "BUG: WUSB Cluster IDs not released on exit: %*pb\n",
-                      CLUSTER_IDS, wusb_cluster_id_table);
-               WARN_ON(1);
-       }
-       usb_unregister_notify(&wusb_usb_notifier);
-       destroy_workqueue(wusbd);
-       wusb_crypto_exit();
-}
-module_exit(wusbcore_exit);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Wireless USB core");
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h
deleted file mode 100644 (file)
index 7681d79..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Host Controller
- * Common infrastructure for WHCI and HWA WUSB-HC drivers
- *
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This driver implements parts common to all Wireless USB Host
- * Controllers (struct wusbhc, embedding a struct usb_hcd) and is used
- * by:
- *
- *   - hwahc: HWA, USB-dongle that implements a Wireless USB host
- *     controller, (Wireless USB 1.0 Host-Wire-Adapter specification).
- *
- *   - whci: WHCI, a PCI card with a wireless host controller
- *     (Wireless Host Controller Interface 1.0 specification).
- *
- * Check out the Design-overview.txt file in the source documentation
- * for other details on the implementation.
- *
- * Main blocks:
- *
- *  rh         Root Hub emulation (part of the HCD glue)
- *
- *  devconnect Handle all the issues related to device connection,
- *             authentication, disconnection, timeout, reseting,
- *             keepalives, etc.
- *
- *  mmc        MMC IE broadcasting handling
- *
- * A host controller driver just initializes its stuff and as part of
- * that, creates a 'struct wusbhc' instance that handles all the
- * common WUSB mechanisms. Links in the function ops that are specific
- * to it and then registers the host controller. Ready to run.
- */
-
-#ifndef __WUSBHC_H__
-#define __WUSBHC_H__
-
-#include <linux/usb.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/kref.h>
-#include <linux/workqueue.h>
-#include <linux/usb/hcd.h>
-#include <linux/uwb.h>
-#include <linux/usb/wusb.h>
-
-/*
- * Time from a WUSB channel stop request to the last transmitted MMC.
- *
- * This needs to be > 4.096 ms in case no MMCs can be transmitted in
- * zone 0.
- */
-#define WUSB_CHANNEL_STOP_DELAY_MS 8
-#define WUSB_RETRY_COUNT_MAX 15
-#define WUSB_RETRY_COUNT_INFINITE 0
-
-/**
- * Wireless USB device
- *
- * Describe a WUSB device connected to the cluster. This struct
- * belongs to the 'struct wusb_port' it is attached to and it is
- * responsible for putting and clearing the pointer to it.
- *
- * Note this "complements" the 'struct usb_device' that the usb_hcd
- * keeps for each connected USB device. However, it extends some
- * information that is not available (there is no hcpriv ptr in it!)
- * *and* most importantly, it's life cycle is different. It is created
- * as soon as we get a DN_Connect (connect request notification) from
- * the device through the WUSB host controller; the USB stack doesn't
- * create the device until we authenticate it. FIXME: this will
- * change.
- *
- * @bos:    This is allocated when the BOS descriptors are read from
- *          the device and freed upon the wusb_dev struct dying.
- * @wusb_cap_descr: points into @bos, and has been verified to be size
- *                  safe.
- */
-struct wusb_dev {
-       struct kref refcnt;
-       struct wusbhc *wusbhc;
-       struct list_head cack_node;     /* Connect-Ack list */
-       struct list_head rekey_node;    /* GTK rekey list */
-       u8 port_idx;
-       u8 addr;
-       u8 beacon_type:4;
-       struct usb_encryption_descriptor ccm1_etd;
-       struct wusb_ckhdid cdid;
-       unsigned long entry_ts;
-       struct usb_bos_descriptor *bos;
-       struct usb_wireless_cap_descriptor *wusb_cap_descr;
-       struct uwb_mas_bm availability;
-       struct work_struct devconnect_acked_work;
-       struct usb_device *usb_dev;
-};
-
-#define WUSB_DEV_ADDR_UNAUTH 0x80
-
-static inline void wusb_dev_init(struct wusb_dev *wusb_dev)
-{
-       kref_init(&wusb_dev->refcnt);
-       /* no need to init the cack_node */
-}
-
-extern void wusb_dev_destroy(struct kref *_wusb_dev);
-
-static inline struct wusb_dev *wusb_dev_get(struct wusb_dev *wusb_dev)
-{
-       kref_get(&wusb_dev->refcnt);
-       return wusb_dev;
-}
-
-static inline void wusb_dev_put(struct wusb_dev *wusb_dev)
-{
-       kref_put(&wusb_dev->refcnt, wusb_dev_destroy);
-}
-
-/**
- * Wireless USB Host Controller root hub "fake" ports
- * (state and device information)
- *
- * Wireless USB is wireless, so there are no ports; but we
- * fake'em. Each RC can connect a max of devices at the same time
- * (given in the Wireless Adapter descriptor, bNumPorts or WHCI's
- * caps), referred to in wusbhc->ports_max.
- *
- * See rh.c for more information.
- *
- * The @status and @change use the same bits as in USB2.0[11.24.2.7],
- * so we don't have to do much when getting the port's status.
- *
- * WUSB1.0[7.1], USB2.0[11.24.2.7.1,fig 11-10],
- * include/linux/usb_ch9.h (#define USB_PORT_STAT_*)
- */
-struct wusb_port {
-       u16 status;
-       u16 change;
-       struct wusb_dev *wusb_dev;      /* connected device's info */
-       u32 ptk_tkid;
-};
-
-/**
- * WUSB Host Controller specifics
- *
- * All fields that are common to all Wireless USB controller types
- * (HWA and WHCI) are grouped here. Host Controller
- * functions/operations that only deal with general Wireless USB HC
- * issues use this data type to refer to the host.
- *
- * @usb_hcd       Instantiation of a USB host controller
- *                 (initialized by upper layer [HWA=HC or WHCI].
- *
- * @dev                   Device that implements this; initialized by the
- *                 upper layer (HWA-HC, WHCI...); this device should
- *                 have a refcount.
- *
- * @trust_timeout  After this time without hearing for device
- *                 activity, we consider the device gone and we have to
- *                 re-authenticate.
- *
- *                 Can be accessed w/o locking--however, read to a
- *                 local variable then use.
- *
- * @chid           WUSB Cluster Host ID: this is supposed to be a
- *                 unique value that doesn't change across reboots (so
- *                 that your devices do not require re-association).
- *
- *                 Read/Write protected by @mutex
- *
- * @dev_info       This array has ports_max elements. It is used to
- *                 give the HC information about the WUSB devices (see
- *                 'struct wusb_dev_info').
- *
- *                For HWA we need to allocate it in heap; for WHCI it
- *                 needs to be permanently mapped, so we keep it for
- *                 both and make it easy. Call wusbhc->dev_info_set()
- *                 to update an entry.
- *
- * @ports_max     Number of simultaneous device connections (fake
- *                 ports) this HC will take. Read-only.
- *
- * @port          Array of port status for each fake root port. Guaranteed to
- *                 always be the same length during device existence
- *                 [this allows for some unlocked but referenced reading].
- *
- * @mmcies_max    Max number of Information Elements this HC can send
- *                 in its MMC. Read-only.
- *
- * @start          Start the WUSB channel.
- *
- * @stop           Stop the WUSB channel after the specified number of
- *                 milliseconds.  Channel Stop IEs should be transmitted
- *                 as required by [WUSB] 4.16.2.1.
- *
- * @mmcie_add     HC specific operation (WHCI or HWA) for adding an
- *                 MMCIE.
- *
- * @mmcie_rm      HC specific operation (WHCI or HWA) for removing an
- *                 MMCIE.
- *
- * @set_ptk:       Set the PTK and enable encryption for a device. Or, if
- *                 the supplied key is NULL, disable encryption for that
- *                 device.
- *
- * @set_gtk:       Set the GTK to be used for all future broadcast packets
- *                 (i.e., MMCs).  With some hardware, setting the GTK may start
- *                 MMC transmission.
- *
- * NOTE:
- *
- *  - If wusb_dev->usb_dev is not NULL, then usb_dev is valid
- *    (wusb_dev has a refcount on it). Likewise, if usb_dev->wusb_dev
- *    is not NULL, usb_dev->wusb_dev is valid (usb_dev keeps a
- *    refcount on it).
- *
- *    Most of the times when you need to use it, it will be non-NULL,
- *    so there is no real need to check for it (wusb_dev will
- *    disappear before usb_dev).
- *
- *  - The following fields need to be filled out before calling
- *    wusbhc_create(): ports_max, mmcies_max, mmcie_{add,rm}.
- *
- *  - there is no wusbhc_init() method, we do everything in
- *    wusbhc_create().
- *
- *  - Creation is done in two phases, wusbhc_create() and
- *    wusbhc_create_b(); b are the parts that need to be called after
- *    calling usb_hcd_add(&wusbhc->usb_hcd).
- */
-struct wusbhc {
-       struct usb_hcd usb_hcd;         /* HAS TO BE 1st */
-       struct device *dev;
-       struct uwb_rc *uwb_rc;
-       struct uwb_pal pal;
-
-       unsigned trust_timeout;                 /* in jiffies */
-       struct wusb_ckhdid chid;
-       uint8_t phy_rate;
-       uint8_t dnts_num_slots;
-       uint8_t dnts_interval;
-       uint8_t retry_count;
-       struct wuie_host_info *wuie_host_info;
-
-       struct mutex mutex;                     /* locks everything else */
-       u16 cluster_id;                         /* Wireless USB Cluster ID */
-       struct wusb_port *port;                 /* Fake port status handling */
-       struct wusb_dev_info *dev_info;         /* for Set Device Info mgmt */
-       u8 ports_max;
-       unsigned active:1;                      /* currently xmit'ing MMCs */
-       struct wuie_keep_alive keep_alive_ie;   /* protected by mutex */
-       struct delayed_work keep_alive_timer;
-       struct list_head cack_list;             /* Connect acknowledging */
-       size_t cack_count;                      /* protected by 'mutex' */
-       struct wuie_connect_ack cack_ie;
-       struct uwb_rsv *rsv;            /* cluster bandwidth reservation */
-
-       struct mutex mmcie_mutex;               /* MMC WUIE handling */
-       struct wuie_hdr **mmcie;                /* WUIE array */
-       u8 mmcies_max;
-       /* FIXME: make wusbhc_ops? */
-       int (*start)(struct wusbhc *wusbhc);
-       void (*stop)(struct wusbhc *wusbhc, int delay);
-       int (*mmcie_add)(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
-                        u8 handle, struct wuie_hdr *wuie);
-       int (*mmcie_rm)(struct wusbhc *wusbhc, u8 handle);
-       int (*dev_info_set)(struct wusbhc *, struct wusb_dev *wusb_dev);
-       int (*bwa_set)(struct wusbhc *wusbhc, s8 stream_index,
-                      const struct uwb_mas_bm *);
-       int (*set_ptk)(struct wusbhc *wusbhc, u8 port_idx,
-                      u32 tkid, const void *key, size_t key_size);
-       int (*set_gtk)(struct wusbhc *wusbhc,
-                      u32 tkid, const void *key, size_t key_size);
-       int (*set_num_dnts)(struct wusbhc *wusbhc, u8 interval, u8 slots);
-
-       struct {
-               struct usb_key_descriptor descr;
-               u8 data[16];                            /* GTK key data */
-       } __attribute__((packed)) gtk;
-       u8 gtk_index;
-       u32 gtk_tkid;
-
-       /* workqueue for WUSB security related tasks. */
-       struct workqueue_struct *wq_security;
-       struct work_struct gtk_rekey_work;
-
-       struct usb_encryption_descriptor *ccm1_etd;
-};
-
-#define usb_hcd_to_wusbhc(u) container_of((u), struct wusbhc, usb_hcd)
-
-
-extern int wusbhc_create(struct wusbhc *);
-extern int wusbhc_b_create(struct wusbhc *);
-extern void wusbhc_b_destroy(struct wusbhc *);
-extern void wusbhc_destroy(struct wusbhc *);
-extern int wusb_dev_sysfs_add(struct wusbhc *, struct usb_device *,
-                             struct wusb_dev *);
-extern void wusb_dev_sysfs_rm(struct wusb_dev *);
-extern int wusbhc_sec_create(struct wusbhc *);
-extern int wusbhc_sec_start(struct wusbhc *);
-extern void wusbhc_sec_stop(struct wusbhc *);
-extern void wusbhc_sec_destroy(struct wusbhc *);
-extern void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb,
-                               int status);
-void wusbhc_reset_all(struct wusbhc *wusbhc);
-
-int wusbhc_pal_register(struct wusbhc *wusbhc);
-void wusbhc_pal_unregister(struct wusbhc *wusbhc);
-
-/*
- * Return @usb_dev's @usb_hcd (properly referenced) or NULL if gone
- *
- * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr)
- *
- * This is a safe assumption as @usb_dev->bus is referenced all the
- * time during the @usb_dev life cycle.
- */
-static inline
-struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev)
-{
-       struct usb_hcd *usb_hcd;
-       usb_hcd = bus_to_hcd(usb_dev->bus);
-       return usb_get_hcd(usb_hcd);
-}
-
-/*
- * Increment the reference count on a wusbhc.
- *
- * @wusbhc's life cycle is identical to that of the underlying usb_hcd.
- */
-static inline struct wusbhc *wusbhc_get(struct wusbhc *wusbhc)
-{
-       return usb_get_hcd(&wusbhc->usb_hcd) ? wusbhc : NULL;
-}
-
-/*
- * Return the wusbhc associated to a @usb_dev
- *
- * @usb_dev: USB device, UNLOCKED and referenced (or otherwise, safe ptr)
- *
- * @returns: wusbhc for @usb_dev; NULL if the @usb_dev is being torn down.
- *           WARNING: referenced at the usb_hcd level, unlocked
- *
- * FIXME: move offline
- */
-static inline struct wusbhc *wusbhc_get_by_usb_dev(struct usb_device *usb_dev)
-{
-       struct wusbhc *wusbhc = NULL;
-       struct usb_hcd *usb_hcd;
-       if (usb_dev->devnum > 1 && !usb_dev->wusb) {
-               /* but root hubs */
-               dev_err(&usb_dev->dev, "devnum %d wusb %d\n", usb_dev->devnum,
-                       usb_dev->wusb);
-               BUG_ON(usb_dev->devnum > 1 && !usb_dev->wusb);
-       }
-       usb_hcd = usb_hcd_get_by_usb_dev(usb_dev);
-       if (usb_hcd == NULL)
-               return NULL;
-       BUG_ON(usb_hcd->wireless == 0);
-       return wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-}
-
-
-static inline void wusbhc_put(struct wusbhc *wusbhc)
-{
-       usb_put_hcd(&wusbhc->usb_hcd);
-}
-
-int wusbhc_start(struct wusbhc *wusbhc);
-void wusbhc_stop(struct wusbhc *wusbhc);
-extern int wusbhc_chid_set(struct wusbhc *, const struct wusb_ckhdid *);
-
-/* Device connect handling */
-extern int wusbhc_devconnect_create(struct wusbhc *);
-extern void wusbhc_devconnect_destroy(struct wusbhc *);
-extern int wusbhc_devconnect_start(struct wusbhc *wusbhc);
-extern void wusbhc_devconnect_stop(struct wusbhc *wusbhc);
-extern void wusbhc_handle_dn(struct wusbhc *, u8 srcaddr,
-                            struct wusb_dn_hdr *dn_hdr, size_t size);
-extern void __wusbhc_dev_disable(struct wusbhc *wusbhc, u8 port);
-extern int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,
-                       void *priv);
-extern int wusb_set_dev_addr(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
-                            u8 addr);
-
-/* Wireless USB fake Root Hub methods */
-extern int wusbhc_rh_create(struct wusbhc *);
-extern void wusbhc_rh_destroy(struct wusbhc *);
-
-extern int wusbhc_rh_status_data(struct usb_hcd *, char *);
-extern int wusbhc_rh_control(struct usb_hcd *, u16, u16, u16, char *, u16);
-extern int wusbhc_rh_start_port_reset(struct usb_hcd *, unsigned);
-
-/* MMC handling */
-extern int wusbhc_mmcie_create(struct wusbhc *);
-extern void wusbhc_mmcie_destroy(struct wusbhc *);
-extern int wusbhc_mmcie_set(struct wusbhc *, u8 interval, u8 repeat_cnt,
-                           struct wuie_hdr *);
-extern void wusbhc_mmcie_rm(struct wusbhc *, struct wuie_hdr *);
-
-/* Bandwidth reservation */
-int wusbhc_rsv_establish(struct wusbhc *wusbhc);
-void wusbhc_rsv_terminate(struct wusbhc *wusbhc);
-
-/*
- * I've always said
- * I wanted a wedding in a church...
- *
- * but lately I've been thinking about
- * the Botanical Gardens.
- *
- * We could do it by the tulips.
- * It'll be beautiful
- *
- * --Security!
- */
-extern int wusb_dev_sec_add(struct wusbhc *, struct usb_device *,
-                               struct wusb_dev *);
-extern void wusb_dev_sec_rm(struct wusb_dev *) ;
-extern int wusb_dev_4way_handshake(struct wusbhc *, struct wusb_dev *,
-                                  struct wusb_ckhdid *ck);
-void wusbhc_gtk_rekey(struct wusbhc *wusbhc);
-int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev);
-
-
-/* WUSB Cluster ID handling */
-extern u8 wusb_cluster_id_get(void);
-extern void wusb_cluster_id_put(u8);
-
-/*
- * wusb_port_by_idx - return the port associated to a zero-based port index
- *
- * NOTE: valid without locking as long as wusbhc is referenced (as the
- *       number of ports doesn't change). The data pointed to has to
- *       be verified though :)
- */
-static inline struct wusb_port *wusb_port_by_idx(struct wusbhc *wusbhc,
-                                                u8 port_idx)
-{
-       return &wusbhc->port[port_idx];
-}
-
-/*
- * wusb_port_no_to_idx - Convert port number (per usb_dev->portnum) to
- * a port_idx.
- *
- * USB stack USB ports are 1 based!!
- *
- * NOTE: only valid for WUSB devices!!!
- */
-static inline u8 wusb_port_no_to_idx(u8 port_no)
-{
-       return port_no - 1;
-}
-
-extern struct wusb_dev *__wusb_dev_get_by_usb_dev(struct wusbhc *,
-                                                 struct usb_device *);
-
-/*
- * Return a referenced wusb_dev given a @usb_dev
- *
- * Returns NULL if the usb_dev is being torn down.
- *
- * FIXME: move offline
- */
-static inline
-struct wusb_dev *wusb_dev_get_by_usb_dev(struct usb_device *usb_dev)
-{
-       struct wusbhc *wusbhc;
-       struct wusb_dev *wusb_dev;
-       wusbhc = wusbhc_get_by_usb_dev(usb_dev);
-       if (wusbhc == NULL)
-               return NULL;
-       mutex_lock(&wusbhc->mutex);
-       wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, usb_dev);
-       mutex_unlock(&wusbhc->mutex);
-       wusbhc_put(wusbhc);
-       return wusb_dev;
-}
-
-/* Misc */
-
-extern struct workqueue_struct *wusbd;
-#endif /* #ifndef __WUSBHC_H__ */
diff --git a/drivers/uwb/Kconfig b/drivers/uwb/Kconfig
deleted file mode 100644 (file)
index 259e053..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-# 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
diff --git a/drivers/uwb/Makefile b/drivers/uwb/Makefile
deleted file mode 100644 (file)
index 32f4de7..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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
diff --git a/drivers/uwb/address.c b/drivers/uwb/address.c
deleted file mode 100644 (file)
index 857d5cd..0000000
+++ /dev/null
@@ -1,352 +0,0 @@
-// 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);
diff --git a/drivers/uwb/allocator.c b/drivers/uwb/allocator.c
deleted file mode 100644 (file)
index 2e15901..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-// 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 <linux/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;
-}
diff --git a/drivers/uwb/beacon.c b/drivers/uwb/beacon.c
deleted file mode 100644 (file)
index c483c19..0000000
+++ /dev/null
@@ -1,595 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Beacon management
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- */
-#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/slab.h>
-
-#include "uwb-internal.h"
-
-/* Start Beaconing command structure */
-struct uwb_rc_cmd_start_beacon {
-       struct uwb_rccb rccb;
-       __le16 wBPSTOffset;
-       u8 bChannelNumber;
-} __attribute__((packed));
-
-
-static int uwb_rc_start_beacon(struct uwb_rc *rc, u16 bpst_offset, u8 channel)
-{
-       int result;
-       struct uwb_rc_cmd_start_beacon *cmd;
-       struct uwb_rc_evt_confirm reply;
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
-       cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
-       cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_START_BEACON);
-       cmd->wBPSTOffset = cpu_to_le16(bpst_offset);
-       cmd->bChannelNumber = channel;
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_START_BEACON;
-       result = uwb_rc_cmd(rc, "START-BEACON", &cmd->rccb, sizeof(*cmd),
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(&rc->uwb_dev.dev,
-                       "START-BEACON: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
-               result = -EIO;
-       }
-error_cmd:
-       kfree(cmd);
-       return result;
-}
-
-static int uwb_rc_stop_beacon(struct uwb_rc *rc)
-{
-       int result;
-       struct uwb_rccb *cmd;
-       struct uwb_rc_evt_confirm reply;
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
-       cmd->bCommandType = UWB_RC_CET_GENERAL;
-       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_STOP_BEACON);
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_STOP_BEACON;
-       result = uwb_rc_cmd(rc, "STOP-BEACON", cmd, sizeof(*cmd),
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(&rc->uwb_dev.dev,
-                       "STOP-BEACON: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
-               result = -EIO;
-       }
-error_cmd:
-       kfree(cmd);
-       return result;
-}
-
-/*
- * Start/stop beacons
- *
- * @rc:          UWB Radio Controller to operate on
- * @channel:     UWB channel on which to beacon (WUSB[table
- *               5-12]). If -1, stop beaconing.
- * @bpst_offset: Beacon Period Start Time offset; FIXME-do zero
- *
- * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
- * of a SET IE command after the device sent the first beacon that includes
- * the IEs specified in the SET IE command. So, after we start beaconing we
- * check if there is anything in the IE cache and call the SET IE command
- * if needed.
- */
-int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset)
-{
-       int result;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       dev_dbg(dev, "%s: channel = %d\n", __func__, channel);
-       if (channel < 0)
-               channel = -1;
-       if (channel == -1)
-               result = uwb_rc_stop_beacon(rc);
-       else {
-               /* channel >= 0...dah */
-               result = uwb_rc_start_beacon(rc, bpst_offset, channel);
-               if (result < 0) {
-                       dev_err(dev, "Cannot start beaconing: %d\n", result);
-                       return result;
-               }
-               if (le16_to_cpu(rc->ies->wIELength) > 0) {
-                       result = uwb_rc_set_ie(rc, rc->ies);
-                       if (result < 0) {
-                               dev_err(dev, "Cannot set new IE on device: "
-                                       "%d\n", result);
-                               result = uwb_rc_stop_beacon(rc);
-                               channel = -1;
-                               bpst_offset = 0;
-                       }
-               }
-       }
-
-       if (result >= 0)
-               rc->beaconing = channel;
-       return result;
-}
-
-/*
- * Beacon cache
- *
- * The purpose of this is to speed up the lookup of becon information
- * when a new beacon arrives. The UWB Daemon uses it also to keep a
- * tab of which devices are in radio distance and which not. When a
- * device's beacon stays present for more than a certain amount of
- * time, it is considered a new, usable device. When a beacon ceases
- * to be received for a certain amount of time, it is considered that
- * the device is gone.
- *
- * FIXME: use an allocator for the entries
- * FIXME: use something faster for search than a list
- */
-
-void uwb_bce_kfree(struct kref *_bce)
-{
-       struct uwb_beca_e *bce = container_of(_bce, struct uwb_beca_e, refcnt);
-
-       kfree(bce->be);
-       kfree(bce);
-}
-
-
-/* Find a beacon by dev addr in the cache */
-static
-struct uwb_beca_e *__uwb_beca_find_bydev(struct uwb_rc *rc,
-                                        const struct uwb_dev_addr *dev_addr)
-{
-       struct uwb_beca_e *bce, *next;
-       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
-               if (!memcmp(&bce->dev_addr, dev_addr, sizeof(bce->dev_addr)))
-                       goto out;
-       }
-       bce = NULL;
-out:
-       return bce;
-}
-
-/* Find a beacon by dev addr in the cache */
-static
-struct uwb_beca_e *__uwb_beca_find_bymac(struct uwb_rc *rc,
-                                        const struct uwb_mac_addr *mac_addr)
-{
-       struct uwb_beca_e *bce, *next;
-       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
-               if (!memcmp(bce->mac_addr, mac_addr->data,
-                           sizeof(struct uwb_mac_addr)))
-                       goto out;
-       }
-       bce = NULL;
-out:
-       return bce;
-}
-
-/**
- * uwb_dev_get_by_devaddr - get a UWB device with a specific DevAddr
- * @rc:      the radio controller that saw the device
- * @devaddr: DevAddr of the UWB device to find
- *
- * There may be more than one matching device (in the case of a
- * DevAddr conflict), but only the first one is returned.
- */
-struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
-                                      const struct uwb_dev_addr *devaddr)
-{
-       struct uwb_dev *found = NULL;
-       struct uwb_beca_e *bce;
-
-       mutex_lock(&rc->uwb_beca.mutex);
-       bce = __uwb_beca_find_bydev(rc, devaddr);
-       if (bce)
-               found = uwb_dev_try_get(rc, bce->uwb_dev);
-       mutex_unlock(&rc->uwb_beca.mutex);
-
-       return found;
-}
-
-/**
- * uwb_dev_get_by_macaddr - get a UWB device with a specific EUI-48
- * @rc:      the radio controller that saw the device
- * @devaddr: EUI-48 of the UWB device to find
- */
-struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
-                                      const struct uwb_mac_addr *macaddr)
-{
-       struct uwb_dev *found = NULL;
-       struct uwb_beca_e *bce;
-
-       mutex_lock(&rc->uwb_beca.mutex);
-       bce = __uwb_beca_find_bymac(rc, macaddr);
-       if (bce)
-               found = uwb_dev_try_get(rc, bce->uwb_dev);
-       mutex_unlock(&rc->uwb_beca.mutex);
-
-       return found;
-}
-
-/* Initialize a beacon cache entry */
-static void uwb_beca_e_init(struct uwb_beca_e *bce)
-{
-       mutex_init(&bce->mutex);
-       kref_init(&bce->refcnt);
-       stats_init(&bce->lqe_stats);
-       stats_init(&bce->rssi_stats);
-}
-
-/*
- * Add a beacon to the cache
- *
- * @be:         Beacon event information
- * @bf:         Beacon frame (part of b, really)
- * @ts_jiffies: Timestamp (in jiffies) when the beacon was received
- */
-static
-struct uwb_beca_e *__uwb_beca_add(struct uwb_rc *rc,
-                                 struct uwb_rc_evt_beacon *be,
-                                 struct uwb_beacon_frame *bf,
-                                 unsigned long ts_jiffies)
-{
-       struct uwb_beca_e *bce;
-
-       bce = kzalloc(sizeof(*bce), GFP_KERNEL);
-       if (bce == NULL)
-               return NULL;
-       uwb_beca_e_init(bce);
-       bce->ts_jiffies = ts_jiffies;
-       bce->uwb_dev = NULL;
-       list_add(&bce->node, &rc->uwb_beca.list);
-       return bce;
-}
-
-/*
- * Wipe out beacon entries that became stale
- *
- * Remove associated devicest too.
- */
-void uwb_beca_purge(struct uwb_rc *rc)
-{
-       struct uwb_beca_e *bce, *next;
-       unsigned long expires;
-
-       mutex_lock(&rc->uwb_beca.mutex);
-       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
-               expires = bce->ts_jiffies + msecs_to_jiffies(beacon_timeout_ms);
-               if (time_after(jiffies, expires)) {
-                       uwbd_dev_offair(bce);
-               }
-       }
-       mutex_unlock(&rc->uwb_beca.mutex);
-}
-
-/* Clean up the whole beacon cache. Called on shutdown */
-void uwb_beca_release(struct uwb_rc *rc)
-{
-       struct uwb_beca_e *bce, *next;
-
-       mutex_lock(&rc->uwb_beca.mutex);
-       list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) {
-               list_del(&bce->node);
-               uwb_bce_put(bce);
-       }
-       mutex_unlock(&rc->uwb_beca.mutex);
-}
-
-static void uwb_beacon_print(struct uwb_rc *rc, struct uwb_rc_evt_beacon *be,
-                            struct uwb_beacon_frame *bf)
-{
-       char macbuf[UWB_ADDR_STRSIZE];
-       char devbuf[UWB_ADDR_STRSIZE];
-       char dstbuf[UWB_ADDR_STRSIZE];
-
-       uwb_mac_addr_print(macbuf, sizeof(macbuf), &bf->Device_Identifier);
-       uwb_dev_addr_print(devbuf, sizeof(devbuf), &bf->hdr.SrcAddr);
-       uwb_dev_addr_print(dstbuf, sizeof(dstbuf), &bf->hdr.DestAddr);
-       dev_info(&rc->uwb_dev.dev,
-                "BEACON from %s to %s (ch%u offset %u slot %u MAC %s)\n",
-                devbuf, dstbuf, be->bChannelNumber, be->wBPSTOffset,
-                bf->Beacon_Slot_Number, macbuf);
-}
-
-/*
- * @bce: beacon cache entry, referenced
- */
-ssize_t uwb_bce_print_IEs(struct uwb_dev *uwb_dev, struct uwb_beca_e *bce,
-                         char *buf, size_t size)
-{
-       ssize_t result = 0;
-       struct uwb_rc_evt_beacon *be;
-       struct uwb_beacon_frame *bf;
-       int ies_len;
-       struct uwb_ie_hdr *ies;
-
-       mutex_lock(&bce->mutex);
-
-       be = bce->be;
-       if (be) {
-               bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
-               ies_len = be->wBeaconInfoLength - sizeof(struct uwb_beacon_frame);
-               ies = (struct uwb_ie_hdr *)bf->IEData;
-
-               result = uwb_ie_dump_hex(ies, ies_len, buf, size);
-       }
-
-       mutex_unlock(&bce->mutex);
-
-       return result;
-}
-
-/*
- * Verify that the beacon event, frame and IEs are ok
- */
-static int uwb_verify_beacon(struct uwb_rc *rc, struct uwb_event *evt,
-                            struct uwb_rc_evt_beacon *be)
-{
-       int result = -EINVAL;
-       struct uwb_beacon_frame *bf;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       /* Is there enough data to decode a beacon frame? */
-       if (evt->notif.size < sizeof(*be) + sizeof(*bf)) {
-               dev_err(dev, "BEACON event: Not enough data to decode "
-                       "(%zu vs %zu bytes needed)\n", evt->notif.size,
-                       sizeof(*be) + sizeof(*bf));
-               goto error;
-       }
-       /* FIXME: make sure beacon frame IEs are fine and that the whole thing
-        * is consistent */
-       result = 0;
-error:
-       return result;
-}
-
-/*
- * Handle UWB_RC_EVT_BEACON events
- *
- * We check the beacon cache to see how the received beacon fares. If
- * is there already we refresh the timestamp. If not we create a new
- * entry.
- *
- * According to the WHCI and WUSB specs, only one beacon frame is
- * allowed per notification block, so we don't bother about scanning
- * for more.
- */
-int uwbd_evt_handle_rc_beacon(struct uwb_event *evt)
-{
-       int result = -EINVAL;
-       struct uwb_rc *rc;
-       struct uwb_rc_evt_beacon *be;
-       struct uwb_beacon_frame *bf;
-       struct uwb_beca_e *bce;
-
-       rc = evt->rc;
-       be = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon, rceb);
-       result = uwb_verify_beacon(rc, evt, be);
-       if (result < 0)
-               return result;
-
-       /* FIXME: handle alien beacons. */
-       if (be->bBeaconType == UWB_RC_BEACON_TYPE_OL_ALIEN ||
-           be->bBeaconType == UWB_RC_BEACON_TYPE_NOL_ALIEN) {
-               return -ENOSYS;
-       }
-
-       bf = (struct uwb_beacon_frame *) be->BeaconInfo;
-
-       /*
-        * Drop beacons from devices with a NULL EUI-48 -- they cannot
-        * be uniquely identified.
-        *
-        * It's expected that these will all be WUSB devices and they
-        * have a WUSB specific connection method so ignoring them
-        * here shouldn't be a problem.
-        */
-       if (uwb_mac_addr_bcast(&bf->Device_Identifier))
-               return 0;
-
-       mutex_lock(&rc->uwb_beca.mutex);
-       bce = __uwb_beca_find_bymac(rc, &bf->Device_Identifier);
-       if (bce == NULL) {
-               /* Not in there, a new device is pinging */
-               uwb_beacon_print(evt->rc, be, bf);
-               bce = __uwb_beca_add(rc, be, bf, evt->ts_jiffies);
-               if (bce == NULL) {
-                       mutex_unlock(&rc->uwb_beca.mutex);
-                       return -ENOMEM;
-               }
-       }
-       mutex_unlock(&rc->uwb_beca.mutex);
-
-       mutex_lock(&bce->mutex);
-       /* purge old beacon data */
-       kfree(bce->be);
-
-       /* Update commonly used fields */
-       bce->ts_jiffies = evt->ts_jiffies;
-       bce->be = be;
-       bce->dev_addr = bf->hdr.SrcAddr;
-       bce->mac_addr = &bf->Device_Identifier;
-       be->wBPSTOffset = le16_to_cpu(be->wBPSTOffset);
-       be->wBeaconInfoLength = le16_to_cpu(be->wBeaconInfoLength);
-       stats_add_sample(&bce->lqe_stats, be->bLQI - 7);
-       stats_add_sample(&bce->rssi_stats, be->bRSSI + 18);
-
-       /*
-        * This might be a beacon from a new device.
-        */
-       if (bce->uwb_dev == NULL)
-               uwbd_dev_onair(evt->rc, bce);
-
-       mutex_unlock(&bce->mutex);
-
-       return 1; /* we keep the event data */
-}
-
-/*
- * Handle UWB_RC_EVT_BEACON_SIZE events
- *
- * XXXXX
- */
-int uwbd_evt_handle_rc_beacon_size(struct uwb_event *evt)
-{
-       int result = -EINVAL;
-       struct device *dev = &evt->rc->uwb_dev.dev;
-       struct uwb_rc_evt_beacon_size *bs;
-
-       /* Is there enough data to decode the event? */
-       if (evt->notif.size < sizeof(*bs)) {
-               dev_err(dev, "BEACON SIZE notification: Not enough data to "
-                       "decode (%zu vs %zu bytes needed)\n",
-                       evt->notif.size, sizeof(*bs));
-               goto error;
-       }
-       bs = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon_size, rceb);
-       if (0)
-               dev_info(dev, "Beacon size changed to %u bytes "
-                       "(FIXME: action?)\n", le16_to_cpu(bs->wNewBeaconSize));
-       else {
-               /* temporary hack until we do something with this message... */
-               static unsigned count;
-               if (++count % 1000 == 0)
-                       dev_info(dev, "Beacon size changed %u times "
-                               "(FIXME: action?)\n", count);
-       }
-       result = 0;
-error:
-       return result;
-}
-
-/**
- * uwbd_evt_handle_rc_bp_slot_change - handle a BP_SLOT_CHANGE event
- * @evt: the BP_SLOT_CHANGE notification from the radio controller
- *
- * If the event indicates that no beacon period slots were available
- * then radio controller has transitioned to a non-beaconing state.
- * Otherwise, simply save the current beacon slot.
- */
-int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *evt)
-{
-       struct uwb_rc *rc = evt->rc;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_evt_bp_slot_change *bpsc;
-
-       if (evt->notif.size < sizeof(*bpsc)) {
-               dev_err(dev, "BP SLOT CHANGE event: Not enough data\n");
-               return -EINVAL;
-       }
-       bpsc = container_of(evt->notif.rceb, struct uwb_rc_evt_bp_slot_change, rceb);
-
-       if (uwb_rc_evt_bp_slot_change_no_slot(bpsc)) {
-               dev_err(dev, "stopped beaconing: No free slots in BP\n");
-               mutex_lock(&rc->uwb_dev.mutex);
-               rc->beaconing = -1;
-               mutex_unlock(&rc->uwb_dev.mutex);
-       } else
-               rc->uwb_dev.beacon_slot = uwb_rc_evt_bp_slot_change_slot_num(bpsc);
-
-       return 0;
-}
-
-/**
- * Handle UWB_RC_EVT_BPOIE_CHANGE events
- *
- * XXXXX
- */
-struct uwb_ie_bpo {
-       struct uwb_ie_hdr hdr;
-       u8                bp_length;
-       u8                data[];
-} __attribute__((packed));
-
-int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *evt)
-{
-       int result = -EINVAL;
-       struct device *dev = &evt->rc->uwb_dev.dev;
-       struct uwb_rc_evt_bpoie_change *bpoiec;
-       struct uwb_ie_bpo *bpoie;
-       static unsigned count;  /* FIXME: this is a temp hack */
-       size_t iesize;
-
-       /* Is there enough data to decode it? */
-       if (evt->notif.size < sizeof(*bpoiec)) {
-               dev_err(dev, "BPOIEC notification: Not enough data to "
-                       "decode (%zu vs %zu bytes needed)\n",
-                       evt->notif.size, sizeof(*bpoiec));
-               goto error;
-       }
-       bpoiec = container_of(evt->notif.rceb, struct uwb_rc_evt_bpoie_change, rceb);
-       iesize = le16_to_cpu(bpoiec->wBPOIELength);
-       if (iesize < sizeof(*bpoie)) {
-               dev_err(dev, "BPOIEC notification: Not enough IE data to "
-                       "decode (%zu vs %zu bytes needed)\n",
-                       iesize, sizeof(*bpoie));
-               goto error;
-       }
-       if (++count % 1000 == 0)        /* Lame placeholder */
-               dev_info(dev, "BPOIE: %u changes received\n", count);
-       /*
-        * FIXME: At this point we should go over all the IEs in the
-        *        bpoiec->BPOIE array and act on each.
-        */
-       result = 0;
-error:
-       return result;
-}
-
-/*
- * Print beaconing state.
- */
-static ssize_t uwb_rc_beacon_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;
-       ssize_t result;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       result = sprintf(buf, "%d\n", rc->beaconing);
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return result;
-}
-
-/*
- * Start beaconing on the specified channel, or stop beaconing.
- */
-static ssize_t uwb_rc_beacon_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;
-       int channel;
-       ssize_t result = -EINVAL;
-
-       result = sscanf(buf, "%d", &channel);
-       if (result >= 1)
-               result = uwb_radio_force_channel(rc, channel);
-
-       return result < 0 ? result : size;
-}
-DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, uwb_rc_beacon_show, uwb_rc_beacon_store);
diff --git a/drivers/uwb/driver.c b/drivers/uwb/driver.c
deleted file mode 100644 (file)
index 5755c2e..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-// 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");
diff --git a/drivers/uwb/drp-avail.c b/drivers/uwb/drp-avail.c
deleted file mode 100644 (file)
index 02392ab..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-// 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;
-}
diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c
deleted file mode 100644 (file)
index 4b545b4..0000000
+++ /dev/null
@@ -1,305 +0,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 <linux/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);
-               }
-       }
-}
-
diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c
deleted file mode 100644 (file)
index 869987b..0000000
+++ /dev/null
@@ -1,842 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Dynamic Reservation Protocol handling
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "uwb-internal.h"
-
-
-/* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */
-enum uwb_drp_conflict_action {
-       /* Reservation is maintained, no action needed */
-       UWB_DRP_CONFLICT_MANTAIN = 0,
-
-       /* the device shall not transmit frames in conflicting MASs in
-        * the following superframe. If the device is the reservation
-        * target, it shall also set the Reason Code in its DRP IE to
-        * Conflict in its beacon in the following superframe.
-        */
-       UWB_DRP_CONFLICT_ACT1,
-
-       /* the device shall not set the Reservation Status bit to ONE
-        * and shall not transmit frames in conflicting MASs. If the
-        * device is the reservation target, it shall also set the
-        * Reason Code in its DRP IE to Conflict.
-        */
-       UWB_DRP_CONFLICT_ACT2,
-
-       /* the device shall not transmit frames in conflicting MASs in
-        * the following superframe. It shall remove the conflicting
-        * MASs from the reservation or set the Reservation Status to
-        * ZERO in its beacon in the following superframe. If the
-        * device is the reservation target, it shall also set the
-        * Reason Code in its DRP IE to Conflict.
-        */
-       UWB_DRP_CONFLICT_ACT3,
-};
-
-
-static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg,
-                                   struct uwb_rceb *reply, ssize_t reply_size)
-{
-       struct uwb_rc_evt_set_drp_ie *r = (struct uwb_rc_evt_set_drp_ie *)reply;
-       unsigned long flags;
-
-       if (r != NULL) {
-               if (r->bResultCode != UWB_RC_RES_SUCCESS)
-                       dev_err(&rc->uwb_dev.dev, "SET-DRP-IE failed: %s (%d)\n",
-                               uwb_rc_strerror(r->bResultCode), r->bResultCode);
-       } else
-               dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n");
-
-       spin_lock_irqsave(&rc->rsvs_lock, flags);
-       if (rc->set_drp_ie_pending > 1) {
-               rc->set_drp_ie_pending = 0;
-               uwb_rsv_queue_update(rc);
-       } else {
-               rc->set_drp_ie_pending = 0;
-       }
-       spin_unlock_irqrestore(&rc->rsvs_lock, flags);
-}
-
-/**
- * Construct and send the SET DRP IE
- *
- * @rc:         UWB Host controller
- * @returns:    >= 0 number of bytes still available in the beacon
- *              < 0 errno code on error.
- *
- * See WUSB[8.6.2.7]: The host must set all the DRP IEs that it wants the
- * device to include in its beacon at the same time. We thus have to
- * traverse all reservations and include the DRP IEs of all PENDING
- * and NEGOTIATED reservations in a SET DRP command for transmission.
- *
- * A DRP Availability IE is appended.
- *
- * rc->rsvs_mutex is held
- *
- * FIXME We currently ignore the returned value indicating the remaining space
- * in beacon. This could be used to deny reservation requests earlier if
- * determined that they would cause the beacon space to be exceeded.
- */
-int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
-{
-       int result;
-       struct uwb_rc_cmd_set_drp_ie *cmd;
-       struct uwb_rsv *rsv;
-       struct uwb_rsv_move *mv;
-       int num_bytes = 0;
-       u8 *IEDataptr;
-
-       result = -ENOMEM;
-       /* First traverse all reservations to determine memory needed. */
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (rsv->drp_ie != NULL) {
-                       num_bytes += rsv->drp_ie->hdr.length + 2;
-                       if (uwb_rsv_has_two_drp_ies(rsv) &&
-                               (rsv->mv.companion_drp_ie != NULL)) {
-                               mv = &rsv->mv;
-                               num_bytes +=
-                                       mv->companion_drp_ie->hdr.length + 2;
-                       }
-               }
-       }
-       num_bytes += sizeof(rc->drp_avail.ie);
-       cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL);
-       if (cmd == NULL)
-               goto error;
-       cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
-       cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_DRP_IE);
-       cmd->wIELength = num_bytes;
-       IEDataptr = (u8 *)&cmd->IEData[0];
-
-       /* FIXME: DRV avail IE is not always needed */
-       /* put DRP avail IE first */
-       memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie));
-       IEDataptr += sizeof(struct uwb_ie_drp_avail);
-
-       /* Next traverse all reservations to place IEs in allocated memory. */
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (rsv->drp_ie != NULL) {
-                       memcpy(IEDataptr, rsv->drp_ie,
-                              rsv->drp_ie->hdr.length + 2);
-                       IEDataptr += rsv->drp_ie->hdr.length + 2;
-
-                       if (uwb_rsv_has_two_drp_ies(rsv) &&
-                               (rsv->mv.companion_drp_ie != NULL)) {
-                               mv = &rsv->mv;
-                               memcpy(IEDataptr, mv->companion_drp_ie,
-                                      mv->companion_drp_ie->hdr.length + 2);
-                               IEDataptr +=
-                                       mv->companion_drp_ie->hdr.length + 2;
-                       }
-               }
-       }
-
-       result = uwb_rc_cmd_async(rc, "SET-DRP-IE",
-                               &cmd->rccb, sizeof(*cmd) + num_bytes,
-                               UWB_RC_CET_GENERAL, UWB_RC_CMD_SET_DRP_IE,
-                               uwb_rc_set_drp_cmd_done, NULL);
-
-       rc->set_drp_ie_pending = 1;
-
-       kfree(cmd);
-error:
-       return result;
-}
-
-/*
- * Evaluate the action to perform using conflict resolution rules
- *
- * Return a uwb_drp_conflict_action.
- */
-static int evaluate_conflict_action(struct uwb_ie_drp *ext_drp_ie, int ext_beacon_slot,
-                                   struct uwb_rsv *rsv, int our_status)
-{
-       int our_tie_breaker = rsv->tiebreaker;
-       int our_type        = rsv->type;
-       int our_beacon_slot = rsv->rc->uwb_dev.beacon_slot;
-
-       int ext_tie_breaker = uwb_ie_drp_tiebreaker(ext_drp_ie);
-       int ext_status      = uwb_ie_drp_status(ext_drp_ie);
-       int ext_type        = uwb_ie_drp_type(ext_drp_ie);
-
-
-       /* [ECMA-368 2nd Edition] 17.4.6 */
-       if (ext_type == UWB_DRP_TYPE_PCA && our_type == UWB_DRP_TYPE_PCA) {
-               return UWB_DRP_CONFLICT_MANTAIN;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-1 */
-       if (our_type == UWB_DRP_TYPE_ALIEN_BP) {
-               return UWB_DRP_CONFLICT_MANTAIN;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-2 */
-       if (ext_type == UWB_DRP_TYPE_ALIEN_BP) {
-               /* here we know our_type != UWB_DRP_TYPE_ALIEN_BP */
-               return UWB_DRP_CONFLICT_ACT1;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-3 */
-       if (our_status == 0 && ext_status == 1) {
-               return UWB_DRP_CONFLICT_ACT2;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-4 */
-       if (our_status == 1 && ext_status == 0) {
-               return UWB_DRP_CONFLICT_MANTAIN;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-5a */
-       if (our_tie_breaker == ext_tie_breaker &&
-           our_beacon_slot <  ext_beacon_slot) {
-               return UWB_DRP_CONFLICT_MANTAIN;
-       }
-
-       /* [ECMA-368 2nd Edition] 17.4.6-5b */
-       if (our_tie_breaker != ext_tie_breaker &&
-           our_beacon_slot >  ext_beacon_slot) {
-               return UWB_DRP_CONFLICT_MANTAIN;
-       }
-
-       if (our_status == 0) {
-               if (our_tie_breaker == ext_tie_breaker) {
-                       /* [ECMA-368 2nd Edition] 17.4.6-6a */
-                       if (our_beacon_slot > ext_beacon_slot) {
-                               return UWB_DRP_CONFLICT_ACT2;
-                       }
-               } else  {
-                       /* [ECMA-368 2nd Edition] 17.4.6-6b */
-                       if (our_beacon_slot < ext_beacon_slot) {
-                               return UWB_DRP_CONFLICT_ACT2;
-                       }
-               }
-       } else {
-               if (our_tie_breaker == ext_tie_breaker) {
-                       /* [ECMA-368 2nd Edition] 17.4.6-7a */
-                       if (our_beacon_slot > ext_beacon_slot) {
-                               return UWB_DRP_CONFLICT_ACT3;
-                       }
-               } else {
-                       /* [ECMA-368 2nd Edition] 17.4.6-7b */
-                       if (our_beacon_slot < ext_beacon_slot) {
-                               return UWB_DRP_CONFLICT_ACT3;
-                       }
-               }
-       }
-       return UWB_DRP_CONFLICT_MANTAIN;
-}
-
-static void handle_conflict_normal(struct uwb_ie_drp *drp_ie,
-                                  int ext_beacon_slot,
-                                  struct uwb_rsv *rsv,
-                                  struct uwb_mas_bm *conflicting_mas)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct uwb_rsv_move *mv = &rsv->mv;
-       struct uwb_drp_backoff_win *bow = &rc->bow;
-       int action;
-
-       action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, uwb_rsv_status(rsv));
-
-       if (uwb_rsv_is_owner(rsv)) {
-               switch(action) {
-               case UWB_DRP_CONFLICT_ACT2:
-                       /* try move */
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_TO_BE_MOVED);
-                       if (bow->can_reserve_extra_mases == false)
-                               uwb_rsv_backoff_win_increment(rc);
-
-                       break;
-               case UWB_DRP_CONFLICT_ACT3:
-                       uwb_rsv_backoff_win_increment(rc);
-                       /* drop some mases with reason modified */
-                       /* put in the companion the mases to be dropped */
-                       bitmap_and(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS);
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
-               default:
-                       break;
-               }
-       } else {
-               switch(action) {
-               case UWB_DRP_CONFLICT_ACT2:
-               case UWB_DRP_CONFLICT_ACT3:
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
-               default:
-                       break;
-               }
-
-       }
-
-}
-
-static void handle_conflict_expanding(struct uwb_ie_drp *drp_ie, int ext_beacon_slot,
-                                     struct uwb_rsv *rsv, bool companion_only,
-                                     struct uwb_mas_bm *conflicting_mas)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct uwb_drp_backoff_win *bow = &rc->bow;
-       struct uwb_rsv_move *mv = &rsv->mv;
-       int action;
-
-       if (companion_only) {
-               /* status of companion is 0 at this point */
-               action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, 0);
-               if (uwb_rsv_is_owner(rsv)) {
-                       switch(action) {
-                       case UWB_DRP_CONFLICT_ACT2:
-                       case UWB_DRP_CONFLICT_ACT3:
-                               uwb_rsv_set_state(rsv,
-                                               UWB_RSV_STATE_O_ESTABLISHED);
-                               rsv->needs_release_companion_mas = false;
-                               if (bow->can_reserve_extra_mases == false)
-                                       uwb_rsv_backoff_win_increment(rc);
-                               uwb_drp_avail_release(rsv->rc,
-                                               &rsv->mv.companion_mas);
-                       }
-               } else { /* rsv is target */
-                       switch(action) {
-                       case UWB_DRP_CONFLICT_ACT2:
-                       case UWB_DRP_CONFLICT_ACT3:
-                               uwb_rsv_set_state(rsv,
-                                       UWB_RSV_STATE_T_EXPANDING_CONFLICT);
-                                /* send_drp_avail_ie = true; */
-                       }
-               }
-       } else { /* also base part of the reservation is conflicting */
-               if (uwb_rsv_is_owner(rsv)) {
-                       uwb_rsv_backoff_win_increment(rc);
-                       /* remove companion part */
-                       uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
-
-                       /* drop some mases with reason modified */
-
-                       /* put in the companion the mases to be dropped */
-                       bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm,
-                                       conflicting_mas->bm, UWB_NUM_MAS);
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
-               } else { /* it is a target rsv */
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
-                        /* send_drp_avail_ie = true; */
-               }
-       }
-}
-
-static void uwb_drp_handle_conflict_rsv(struct uwb_rc *rc, struct uwb_rsv *rsv,
-                                       struct uwb_rc_evt_drp *drp_evt,
-                                       struct uwb_ie_drp *drp_ie,
-                                       struct uwb_mas_bm *conflicting_mas)
-{
-       struct uwb_rsv_move *mv;
-
-       /* check if the conflicting reservation has two drp_ies */
-       if (uwb_rsv_has_two_drp_ies(rsv)) {
-               mv = &rsv->mv;
-               if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
-                                                               UWB_NUM_MAS)) {
-                       handle_conflict_expanding(drp_ie,
-                                               drp_evt->beacon_slot_number,
-                                               rsv, false, conflicting_mas);
-               } else {
-                       if (bitmap_intersects(mv->companion_mas.bm,
-                                       conflicting_mas->bm, UWB_NUM_MAS)) {
-                               handle_conflict_expanding(
-                                       drp_ie, drp_evt->beacon_slot_number,
-                                       rsv, true, conflicting_mas);
-                       }
-               }
-       } else if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
-                                                       UWB_NUM_MAS)) {
-               handle_conflict_normal(drp_ie, drp_evt->beacon_slot_number,
-                                       rsv, conflicting_mas);
-       }
-}
-
-static void uwb_drp_handle_all_conflict_rsv(struct uwb_rc *rc,
-                                           struct uwb_rc_evt_drp *drp_evt,
-                                           struct uwb_ie_drp *drp_ie,
-                                           struct uwb_mas_bm *conflicting_mas)
-{
-       struct uwb_rsv *rsv;
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie,
-                                                       conflicting_mas);
-       }
-}
-
-static void uwb_drp_process_target_accepted(struct uwb_rc *rc,
-       struct uwb_rsv *rsv, struct uwb_rc_evt_drp *drp_evt,
-       struct uwb_ie_drp *drp_ie, struct uwb_mas_bm *mas)
-{
-       struct uwb_rsv_move *mv = &rsv->mv;
-       int status;
-
-       status = uwb_ie_drp_status(drp_ie);
-
-       if (rsv->state == UWB_RSV_STATE_T_CONFLICT) {
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
-               return;
-       }
-
-       if (rsv->state == UWB_RSV_STATE_T_EXPANDING_ACCEPTED) {
-               /* drp_ie is companion */
-               if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
-                       /* stroke companion */
-                       uwb_rsv_set_state(rsv,
-                               UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
-               }
-       } else {
-               if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
-                       if (uwb_drp_avail_reserve_pending(rc, mas) == -EBUSY) {
-                               /* FIXME: there is a conflict, find
-                                * the conflicting reservations and
-                                * take a sensible action. Consider
-                                * that in drp_ie there is the
-                                * "neighbour" */
-                               uwb_drp_handle_all_conflict_rsv(rc, drp_evt,
-                                               drp_ie, mas);
-                       } else {
-                               /* accept the extra reservation */
-                               bitmap_copy(mv->companion_mas.bm, mas->bm,
-                                                               UWB_NUM_MAS);
-                               uwb_rsv_set_state(rsv,
-                                       UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
-                       }
-               } else {
-                       if (status) {
-                               uwb_rsv_set_state(rsv,
-                                               UWB_RSV_STATE_T_ACCEPTED);
-                       }
-               }
-
-       }
-}
-
-/*
- * Based on the DRP IE, transition a target reservation to a new
- * state.
- */
-static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv,
-                  struct uwb_ie_drp *drp_ie, struct uwb_rc_evt_drp *drp_evt)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rsv_move *mv = &rsv->mv;
-       int status;
-       enum uwb_drp_reason reason_code;
-       struct uwb_mas_bm mas;
-
-       status = uwb_ie_drp_status(drp_ie);
-       reason_code = uwb_ie_drp_reason_code(drp_ie);
-       uwb_drp_ie_to_bm(&mas, drp_ie);
-
-       switch (reason_code) {
-       case UWB_DRP_REASON_ACCEPTED:
-               uwb_drp_process_target_accepted(rc, rsv, drp_evt, drp_ie, &mas);
-               break;
-
-       case UWB_DRP_REASON_MODIFIED:
-               /* check to see if we have already modified the reservation */
-               if (bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
-                       break;
-               }
-
-               /* find if the owner wants to expand or reduce */
-               if (bitmap_subset(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) {
-                       /* owner is reducing */
-                       bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mas.bm,
-                               UWB_NUM_MAS);
-                       uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
-               }
-
-               bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS);
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_RESIZED);
-               break;
-       default:
-               dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
-                        reason_code, status);
-       }
-}
-
-static void uwb_drp_process_owner_accepted(struct uwb_rsv *rsv,
-                                               struct uwb_mas_bm *mas)
-{
-       struct uwb_rsv_move *mv = &rsv->mv;
-
-       switch (rsv->state) {
-       case UWB_RSV_STATE_O_PENDING:
-       case UWB_RSV_STATE_O_INITIATED:
-       case UWB_RSV_STATE_O_ESTABLISHED:
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-               break;
-       case UWB_RSV_STATE_O_MODIFIED:
-               if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-               else
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
-               break;
-
-       case UWB_RSV_STATE_O_MOVE_REDUCING: /* shouldn' t be a problem */
-               if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-               else
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
-               break;
-       case UWB_RSV_STATE_O_MOVE_EXPANDING:
-               if (bitmap_equal(mas->bm, mv->companion_mas.bm, UWB_NUM_MAS)) {
-                       /* Companion reservation accepted */
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
-               } else {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
-               }
-               break;
-       case UWB_RSV_STATE_O_MOVE_COMBINING:
-               if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
-               else
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
-               break;
-       default:
-               break;
-       }
-}
-/*
- * Based on the DRP IE, transition an owner reservation to a new
- * state.
- */
-static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv,
-                                 struct uwb_dev *src, struct uwb_ie_drp *drp_ie,
-                                 struct uwb_rc_evt_drp *drp_evt)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       int status;
-       enum uwb_drp_reason reason_code;
-       struct uwb_mas_bm mas;
-
-       status = uwb_ie_drp_status(drp_ie);
-       reason_code = uwb_ie_drp_reason_code(drp_ie);
-       uwb_drp_ie_to_bm(&mas, drp_ie);
-
-       if (status) {
-               switch (reason_code) {
-               case UWB_DRP_REASON_ACCEPTED:
-                       uwb_drp_process_owner_accepted(rsv, &mas);
-                       break;
-               default:
-                       dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
-                                reason_code, status);
-               }
-       } else {
-               switch (reason_code) {
-               case UWB_DRP_REASON_PENDING:
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_PENDING);
-                       break;
-               case UWB_DRP_REASON_DENIED:
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-                       break;
-               case UWB_DRP_REASON_CONFLICT:
-                       /* resolve the conflict */
-                       bitmap_complement(mas.bm, src->last_availability_bm,
-                                         UWB_NUM_MAS);
-                       uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, &mas);
-                       break;
-               default:
-                       dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
-                                reason_code, status);
-               }
-       }
-}
-
-static void uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien *cnflt)
-{
-       unsigned timeout_us = UWB_MAX_LOST_BEACONS * UWB_SUPERFRAME_LENGTH_US;
-       mod_timer(&cnflt->timer, jiffies + usecs_to_jiffies(timeout_us));
-}
-
-static void uwb_cnflt_update_work(struct work_struct *work)
-{
-       struct uwb_cnflt_alien *cnflt = container_of(work,
-                                                    struct uwb_cnflt_alien,
-                                                    cnflt_update_work);
-       struct uwb_cnflt_alien *c;
-       struct uwb_rc *rc = cnflt->rc;
-
-       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       list_del(&cnflt->rc_node);
-
-       /* update rc global conflicting alien bitmap */
-       bitmap_zero(rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
-
-       list_for_each_entry(c, &rc->cnflt_alien_list, rc_node) {
-               bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm,
-                                               c->mas.bm, UWB_NUM_MAS);
-       }
-
-       queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work,
-                                       usecs_to_jiffies(delay_us));
-
-       kfree(cnflt);
-       mutex_unlock(&rc->rsvs_mutex);
-}
-
-static void uwb_cnflt_timer(struct timer_list *t)
-{
-       struct uwb_cnflt_alien *cnflt = from_timer(cnflt, t, timer);
-
-       queue_work(cnflt->rc->rsv_workq, &cnflt->cnflt_update_work);
-}
-
-/*
- * We have received an DRP_IE of type Alien BP and we need to make
- * sure we do not transmit in conflicting MASs.
- */
-static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_mas_bm mas;
-       struct uwb_cnflt_alien *cnflt;
-       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
-
-       uwb_drp_ie_to_bm(&mas, drp_ie);
-
-       list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) {
-               if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) {
-                       /* Existing alien BP reservation conflicting
-                        * bitmap, just reset the timer */
-                       uwb_cnflt_alien_stroke_timer(cnflt);
-                       return;
-               }
-       }
-
-       /* New alien BP reservation conflicting bitmap */
-
-       /* alloc and initialize new uwb_cnflt_alien */
-       cnflt = kzalloc(sizeof(struct uwb_cnflt_alien), GFP_KERNEL);
-       if (!cnflt) {
-               dev_err(dev, "failed to alloc uwb_cnflt_alien struct\n");
-               return;
-       }
-
-       INIT_LIST_HEAD(&cnflt->rc_node);
-       timer_setup(&cnflt->timer, uwb_cnflt_timer, 0);
-
-       cnflt->rc = rc;
-       INIT_WORK(&cnflt->cnflt_update_work, uwb_cnflt_update_work);
-
-       bitmap_copy(cnflt->mas.bm, mas.bm, UWB_NUM_MAS);
-
-       list_add_tail(&cnflt->rc_node, &rc->cnflt_alien_list);
-
-       /* update rc global conflicting alien bitmap */
-       bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, mas.bm, UWB_NUM_MAS);
-
-       queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us));
-
-       /* start the timer */
-       uwb_cnflt_alien_stroke_timer(cnflt);
-}
-
-static void uwb_drp_process_not_involved(struct uwb_rc *rc,
-                                        struct uwb_rc_evt_drp *drp_evt,
-                                        struct uwb_ie_drp *drp_ie)
-{
-       struct uwb_mas_bm mas;
-
-       uwb_drp_ie_to_bm(&mas, drp_ie);
-       uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas);
-}
-
-static void uwb_drp_process_involved(struct uwb_rc *rc, struct uwb_dev *src,
-                                    struct uwb_rc_evt_drp *drp_evt,
-                                    struct uwb_ie_drp *drp_ie)
-{
-       struct uwb_rsv *rsv;
-
-       rsv = uwb_rsv_find(rc, src, drp_ie);
-       if (!rsv) {
-               /*
-                * No reservation? It's either for a recently
-                * terminated reservation; or the DRP IE couldn't be
-                * processed (e.g., an invalid IE or out of memory).
-                */
-               return;
-       }
-
-       /*
-        * Do nothing with DRP IEs for reservations that have been
-        * terminated.
-        */
-       if (rsv->state == UWB_RSV_STATE_NONE) {
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-               return;
-       }
-
-       if (uwb_ie_drp_owner(drp_ie))
-               uwb_drp_process_target(rc, rsv, drp_ie, drp_evt);
-       else
-               uwb_drp_process_owner(rc, rsv, src, drp_ie, drp_evt);
-
-}
-
-
-static bool uwb_drp_involves_us(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
-{
-       return uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, &drp_ie->dev_addr) == 0;
-}
-
-/*
- * Process a received DRP IE.
- */
-static void uwb_drp_process(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
-                           struct uwb_dev *src, struct uwb_ie_drp *drp_ie)
-{
-       if (uwb_ie_drp_type(drp_ie) == UWB_DRP_TYPE_ALIEN_BP)
-               uwb_drp_handle_alien_drp(rc, drp_ie);
-       else if (uwb_drp_involves_us(rc, drp_ie))
-               uwb_drp_process_involved(rc, src, drp_evt, drp_ie);
-       else
-               uwb_drp_process_not_involved(rc, drp_evt, drp_ie);
-}
-
-/*
- * Process a received DRP Availability IE
- */
-static void uwb_drp_availability_process(struct uwb_rc *rc, struct uwb_dev *src,
-                                        struct uwb_ie_drp_avail *drp_availability_ie)
-{
-       bitmap_copy(src->last_availability_bm,
-                   drp_availability_ie->bmp, UWB_NUM_MAS);
-}
-
-/*
- * Process all the DRP IEs (both DRP IEs and the DRP Availability IE)
- * from a device.
- */
-static
-void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
-                        size_t ielen, struct uwb_dev *src_dev)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_ie_hdr *ie_hdr;
-       void *ptr;
-
-       ptr = drp_evt->ie_data;
-       for (;;) {
-               ie_hdr = uwb_ie_next(&ptr, &ielen);
-               if (!ie_hdr)
-                       break;
-
-               switch (ie_hdr->element_id) {
-               case UWB_IE_DRP_AVAILABILITY:
-                       uwb_drp_availability_process(rc, src_dev, (struct uwb_ie_drp_avail *)ie_hdr);
-                       break;
-               case UWB_IE_DRP:
-                       uwb_drp_process(rc, drp_evt, src_dev, (struct uwb_ie_drp *)ie_hdr);
-                       break;
-               default:
-                       dev_warn(dev, "unexpected IE in DRP notification\n");
-                       break;
-               }
-       }
-
-       if (ielen > 0)
-               dev_warn(dev, "%d octets remaining in DRP notification\n",
-                        (int)ielen);
-}
-
-/**
- * uwbd_evt_handle_rc_drp - handle a DRP_IE event
- * @evt: the DRP_IE event from the radio controller
- *
- * This processes DRP notifications from the radio controller, either
- * initiating a new reservation or transitioning an existing
- * reservation into a different state.
- *
- * DRP notifications can occur for three different reasons:
- *
- * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as
- *   the target or source have been received.
- *
- *   These DRP IEs could be new or for an existing reservation.
- *
- *   If the DRP IE for an existing reservation ceases to be to
- *   received for at least mMaxLostBeacons, the reservation should be
- *   considered to be terminated.  Note that the TERMINATE reason (see
- *   below) may not always be signalled (e.g., the remote device has
- *   two or more reservations established with the RC).
- *
- * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon
- *   group conflict with the RC's reservations.
- *
- * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received
- *   from a device (i.e., it's terminated all reservations).
- *
- * Only the software state of the reservations is changed; the setting
- * of the radio controller's DRP IEs is done after all the events in
- * an event buffer are processed.  This saves waiting multiple times
- * for the SET_DRP_IE command to complete.
- */
-int uwbd_evt_handle_rc_drp(struct uwb_event *evt)
-{
-       struct device *dev = &evt->rc->uwb_dev.dev;
-       struct uwb_rc *rc = evt->rc;
-       struct uwb_rc_evt_drp *drp_evt;
-       size_t ielength, bytes_left;
-       struct uwb_dev_addr src_addr;
-       struct uwb_dev *src_dev;
-
-       /* Is there enough data to decode the event (and any IEs in
-          its payload)? */
-       if (evt->notif.size < sizeof(*drp_evt)) {
-               dev_err(dev, "DRP event: Not enough data to decode event "
-                       "[%zu bytes left, %zu needed]\n",
-                       evt->notif.size, sizeof(*drp_evt));
-               return 0;
-       }
-       bytes_left = evt->notif.size - sizeof(*drp_evt);
-       drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp, rceb);
-       ielength = le16_to_cpu(drp_evt->ie_length);
-       if (bytes_left != ielength) {
-               dev_err(dev, "DRP event: Not enough data in payload [%zu"
-                       "bytes left, %zu declared in the event]\n",
-                       bytes_left, ielength);
-               return 0;
-       }
-
-       memcpy(src_addr.data, &drp_evt->src_addr, sizeof(src_addr));
-       src_dev = uwb_dev_get_by_devaddr(rc, &src_addr);
-       if (!src_dev) {
-               /*
-                * A DRP notification from an unrecognized device.
-                *
-                * This is probably from a WUSB device that doesn't
-                * have an EUI-48 and therefore doesn't show up in the
-                * UWB device database.  It's safe to simply ignore
-                * these.
-                */
-               return 0;
-       }
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       /* We do not distinguish from the reason */
-       uwb_drp_process_all(rc, drp_evt, ielength, src_dev);
-
-       mutex_unlock(&rc->rsvs_mutex);
-
-       uwb_dev_put(src_dev);
-       return 0;
-}
diff --git a/drivers/uwb/est.c b/drivers/uwb/est.c
deleted file mode 100644 (file)
index d4141ff..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band Radio Control
- * Event Size Tables management
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- *
- * Infrastructure, code and data tables for guessing the size of
- * events received on the notification endpoints of UWB radio
- * controllers.
- *
- * You define a table of events and for each, its size and how to get
- * the extra size.
- *
- * ENTRY POINTS:
- *
- * uwb_est_{init/destroy}(): To initialize/release the EST subsystem.
- *
- * uwb_est_[u]register(): To un/register event size tables
- *   uwb_est_grow()
- *
- * uwb_est_find_size(): Get the size of an event
- *   uwb_est_get_size()
- */
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-struct uwb_est {
-       u16 type_event_high;
-       u16 vendor, product;
-       u8 entries;
-       const struct uwb_est_entry *entry;
-};
-
-static struct uwb_est *uwb_est;
-static u8 uwb_est_size;
-static u8 uwb_est_used;
-static DEFINE_RWLOCK(uwb_est_lock);
-
-/**
- * WUSB Standard Event Size Table, HWA-RC interface
- *
- * Sizes for events and notifications type 0 (general), high nibble 0.
- */
-static
-struct uwb_est_entry uwb_est_00_00xx[] = {
-       [UWB_RC_EVT_IE_RCV] = {
-               .size = sizeof(struct uwb_rc_evt_ie_rcv),
-               .offset = 1 + offsetof(struct uwb_rc_evt_ie_rcv, wIELength),
-       },
-       [UWB_RC_EVT_BEACON] = {
-               .size = sizeof(struct uwb_rc_evt_beacon),
-               .offset = 1 + offsetof(struct uwb_rc_evt_beacon, wBeaconInfoLength),
-       },
-       [UWB_RC_EVT_BEACON_SIZE] = {
-               .size = sizeof(struct uwb_rc_evt_beacon_size),
-       },
-       [UWB_RC_EVT_BPOIE_CHANGE] = {
-               .size = sizeof(struct uwb_rc_evt_bpoie_change),
-               .offset = 1 + offsetof(struct uwb_rc_evt_bpoie_change,
-                                      wBPOIELength),
-       },
-       [UWB_RC_EVT_BP_SLOT_CHANGE] = {
-               .size = sizeof(struct uwb_rc_evt_bp_slot_change),
-       },
-       [UWB_RC_EVT_BP_SWITCH_IE_RCV] = {
-               .size = sizeof(struct uwb_rc_evt_bp_switch_ie_rcv),
-               .offset = 1 + offsetof(struct uwb_rc_evt_bp_switch_ie_rcv, wIELength),
-       },
-       [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
-               .size = sizeof(struct uwb_rc_evt_dev_addr_conflict),
-       },
-       [UWB_RC_EVT_DRP_AVAIL] = {
-               .size = sizeof(struct uwb_rc_evt_drp_avail)
-       },
-       [UWB_RC_EVT_DRP] = {
-               .size = sizeof(struct uwb_rc_evt_drp),
-               .offset = 1 + offsetof(struct uwb_rc_evt_drp, ie_length),
-       },
-       [UWB_RC_EVT_BP_SWITCH_STATUS] = {
-               .size = sizeof(struct uwb_rc_evt_bp_switch_status),
-       },
-       [UWB_RC_EVT_CMD_FRAME_RCV] = {
-               .size = sizeof(struct uwb_rc_evt_cmd_frame_rcv),
-               .offset = 1 + offsetof(struct uwb_rc_evt_cmd_frame_rcv, dataLength),
-       },
-       [UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV] = {
-               .size = sizeof(struct uwb_rc_evt_channel_change_ie_rcv),
-               .offset = 1 + offsetof(struct uwb_rc_evt_channel_change_ie_rcv, wIELength),
-       },
-       [UWB_RC_CMD_CHANNEL_CHANGE] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_DEV_ADDR_MGMT] = {
-               .size = sizeof(struct uwb_rc_evt_dev_addr_mgmt) },
-       [UWB_RC_CMD_GET_IE] = {
-               .size = sizeof(struct uwb_rc_evt_get_ie),
-               .offset = 1 + offsetof(struct uwb_rc_evt_get_ie, wIELength),
-       },
-       [UWB_RC_CMD_RESET] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SCAN] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SET_BEACON_FILTER] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SET_DRP_IE] = {
-               .size = sizeof(struct uwb_rc_evt_set_drp_ie),
-       },
-       [UWB_RC_CMD_SET_IE] = {
-               .size = sizeof(struct uwb_rc_evt_set_ie),
-       },
-       [UWB_RC_CMD_SET_NOTIFICATION_FILTER] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SET_TX_POWER] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SLEEP] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_START_BEACON] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_STOP_BEACON] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_BP_MERGE] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SEND_COMMAND_FRAME] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-       [UWB_RC_CMD_SET_ASIE_NOTIF] = {
-               .size = sizeof(struct uwb_rc_evt_confirm),
-       },
-};
-
-static
-struct uwb_est_entry uwb_est_01_00xx[] = {
-       [UWB_RC_DAA_ENERGY_DETECTED] = {
-               .size = sizeof(struct uwb_rc_evt_daa_energy_detected),
-       },
-       [UWB_RC_SET_DAA_ENERGY_MASK] = {
-               .size = sizeof(struct uwb_rc_evt_set_daa_energy_mask),
-       },
-       [UWB_RC_SET_NOTIFICATION_FILTER_EX] = {
-               .size = sizeof(struct uwb_rc_evt_set_notification_filter_ex),
-       },
-};
-
-/**
- * Initialize the EST subsystem
- *
- * Register the standard tables also.
- *
- * FIXME: tag init
- */
-int uwb_est_create(void)
-{
-       int result;
-
-       uwb_est_size = 2;
-       uwb_est_used = 0;
-       uwb_est = kcalloc(uwb_est_size, sizeof(uwb_est[0]), GFP_KERNEL);
-       if (uwb_est == NULL)
-               return -ENOMEM;
-
-       result = uwb_est_register(UWB_RC_CET_GENERAL, 0, 0xffff, 0xffff,
-                                 uwb_est_00_00xx, ARRAY_SIZE(uwb_est_00_00xx));
-       if (result < 0)
-               goto out;
-       result = uwb_est_register(UWB_RC_CET_EX_TYPE_1, 0, 0xffff, 0xffff,
-                                 uwb_est_01_00xx, ARRAY_SIZE(uwb_est_01_00xx));
-out:
-       return result;
-}
-
-
-/** Clean it up */
-void uwb_est_destroy(void)
-{
-       kfree(uwb_est);
-       uwb_est = NULL;
-       uwb_est_size = uwb_est_used = 0;
-}
-
-
-/**
- * Double the capacity of the EST table
- *
- * @returns 0 if ok, < 0 errno no error.
- */
-static
-int uwb_est_grow(void)
-{
-       size_t actual_size = uwb_est_size * sizeof(uwb_est[0]);
-       void *new = kmalloc_array(2, actual_size, GFP_ATOMIC);
-       if (new == NULL)
-               return -ENOMEM;
-       memcpy(new, uwb_est, actual_size);
-       memset(new + actual_size, 0, actual_size);
-       kfree(uwb_est);
-       uwb_est = new;
-       uwb_est_size *= 2;
-       return 0;
-}
-
-
-/**
- * Register an event size table
- *
- * Makes room for it if the table is full, and then inserts  it in the
- * right position (entries are sorted by type, event_high, vendor and
- * then product).
- *
- * @vendor:  vendor code for matching against the device (0x0000 and
- *           0xffff mean any); use 0x0000 to force all to match without
- *           checking possible vendor specific ones, 0xfffff to match
- *           after checking vendor specific ones.
- *
- * @product: product code from that vendor; same matching rules, use
- *           0x0000 for not allowing vendor specific matches, 0xffff
- *           for allowing.
- *
- * This arragement just makes the tables sort differenty. Because the
- * table is sorted by growing type-event_high-vendor-product, a zero
- * vendor will match before than a 0x456a vendor, that will match
- * before a 0xfffff vendor.
- *
- * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
- */
-/* FIXME: add bus type to vendor/product code */
-int uwb_est_register(u8 type, u8 event_high, u16 vendor, u16 product,
-                    const struct uwb_est_entry *entry, size_t entries)
-{
-       unsigned long flags;
-       unsigned itr;
-       int result = 0;
-
-       write_lock_irqsave(&uwb_est_lock, flags);
-       if (uwb_est_used == uwb_est_size) {
-               result = uwb_est_grow();
-               if (result < 0)
-                       goto out;
-       }
-       /* Find the right spot to insert it in */
-       for (itr = 0; itr < uwb_est_used; itr++)
-               if (uwb_est[itr].type_event_high < type
-                   && uwb_est[itr].vendor < vendor
-                   && uwb_est[itr].product < product)
-                       break;
-
-       /* Shift others to make room for the new one? */
-       if (itr < uwb_est_used)
-               memmove(&uwb_est[itr+1], &uwb_est[itr], uwb_est_used - itr);
-       uwb_est[itr].type_event_high = type << 8 | event_high;
-       uwb_est[itr].vendor = vendor;
-       uwb_est[itr].product = product;
-       uwb_est[itr].entry = entry;
-       uwb_est[itr].entries = entries;
-       uwb_est_used++;
-out:
-       write_unlock_irqrestore(&uwb_est_lock, flags);
-       return result;
-}
-EXPORT_SYMBOL_GPL(uwb_est_register);
-
-
-/**
- * Unregister an event size table
- *
- * This just removes the specified entry and moves the ones after it
- * to fill in the gap. This is needed to keep the list sorted; no
- * reallocation is done to reduce the size of the table.
- *
- * We unregister by all the data we used to register instead of by
- * pointer to the @entry array because we might have used the same
- * table for a bunch of IDs (for example).
- *
- * @returns 0 if ok, < 0 errno on error (-ENOENT if not found).
- */
-int uwb_est_unregister(u8 type, u8 event_high, u16 vendor, u16 product,
-                      const struct uwb_est_entry *entry, size_t entries)
-{
-       unsigned long flags;
-       unsigned itr;
-       struct uwb_est est_cmp = {
-               .type_event_high = type << 8 | event_high,
-               .vendor = vendor,
-               .product = product,
-               .entry = entry,
-               .entries = entries
-       };
-       write_lock_irqsave(&uwb_est_lock, flags);
-       for (itr = 0; itr < uwb_est_used; itr++)
-               if (!memcmp(&uwb_est[itr], &est_cmp, sizeof(est_cmp)))
-                       goto found;
-       write_unlock_irqrestore(&uwb_est_lock, flags);
-       return -ENOENT;
-
-found:
-       if (itr < uwb_est_used - 1)     /* Not last one? move ones above */
-               memmove(&uwb_est[itr], &uwb_est[itr+1], uwb_est_used - itr - 1);
-       uwb_est_used--;
-       write_unlock_irqrestore(&uwb_est_lock, flags);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(uwb_est_unregister);
-
-
-/**
- * Get the size of an event from a table
- *
- * @rceb: pointer to the buffer with the event
- * @rceb_size: size of the area pointed to by @rceb in bytes.
- * @returns: > 0      Size of the event
- *          -ENOSPC  An area big enough was not provided to look
- *                   ahead into the event's guts and guess the size.
- *          -EINVAL  Unknown event code (wEvent).
- *
- * This will look at the received RCEB and guess what is the total
- * size. For variable sized events, it will look further ahead into
- * their length field to see how much data should be read.
- *
- * Note this size is *not* final--the neh (Notification/Event Handle)
- * might specificy an extra size to add.
- */
-static
-ssize_t uwb_est_get_size(struct uwb_rc *uwb_rc, struct uwb_est *est,
-                        u8 event_low, const struct uwb_rceb *rceb,
-                        size_t rceb_size)
-{
-       unsigned offset;
-       ssize_t size;
-       struct device *dev = &uwb_rc->uwb_dev.dev;
-       const struct uwb_est_entry *entry;
-
-       size = -ENOENT;
-       if (event_low >= est->entries) {        /* in range? */
-               dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u out of range\n",
-                       est, est->type_event_high, est->vendor, est->product,
-                       est->entries, event_low);
-               goto out;
-       }
-       size = -ENOENT;
-       entry = &est->entry[event_low];
-       if (entry->size == 0 && entry->offset == 0) {   /* unknown? */
-               dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u unknown\n",
-                       est, est->type_event_high, est->vendor, est->product,
-                       est->entries, event_low);
-               goto out;
-       }
-       offset = entry->offset; /* extra fries with that? */
-       if (offset == 0)
-               size = entry->size;
-       else {
-               /* Ops, got an extra size field at 'offset'--read it */
-               const void *ptr = rceb;
-               size_t type_size = 0;
-               offset--;
-               size = -ENOSPC;                 /* enough data for more? */
-               switch (entry->type) {
-               case UWB_EST_16:  type_size = sizeof(__le16); break;
-               case UWB_EST_8:   type_size = sizeof(u8);     break;
-               default:         BUG();
-               }
-               if (offset + type_size > rceb_size) {
-                       dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: "
-                               "not enough data to read extra size\n",
-                               est, est->type_event_high, est->vendor,
-                               est->product, est->entries);
-                       goto out;
-               }
-               size = entry->size;
-               ptr += offset;
-               switch (entry->type) {
-               case UWB_EST_16:  size += le16_to_cpu(*(__le16 *)ptr); break;
-               case UWB_EST_8:   size += *(u8 *)ptr;                  break;
-               default:         BUG();
-               }
-       }
-out:
-       return size;
-}
-
-
-/**
- * Guesses the size of a WA event
- *
- * @rceb: pointer to the buffer with the event
- * @rceb_size: size of the area pointed to by @rceb in bytes.
- * @returns: > 0      Size of the event
- *          -ENOSPC  An area big enough was not provided to look
- *                   ahead into the event's guts and guess the size.
- *          -EINVAL  Unknown event code (wEvent).
- *
- * This will look at the received RCEB and guess what is the total
- * size by checking all the tables registered with
- * uwb_est_register(). For variable sized events, it will look further
- * ahead into their length field to see how much data should be read.
- *
- * Note this size is *not* final--the neh (Notification/Event Handle)
- * might specificy an extra size to add or replace.
- */
-ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
-                         size_t rceb_size)
-{
-       /* FIXME: add vendor/product data */
-       ssize_t size;
-       struct device *dev = &rc->uwb_dev.dev;
-       unsigned long flags;
-       unsigned itr;
-       u16 type_event_high, event;
-
-       read_lock_irqsave(&uwb_est_lock, flags);
-       size = -ENOSPC;
-       if (rceb_size < sizeof(*rceb))
-               goto out;
-       event = le16_to_cpu(rceb->wEvent);
-       type_event_high = rceb->bEventType << 8 | (event & 0xff00) >> 8;
-       for (itr = 0; itr < uwb_est_used; itr++) {
-               if (uwb_est[itr].type_event_high != type_event_high)
-                       continue;
-               size = uwb_est_get_size(rc, &uwb_est[itr],
-                                       event & 0x00ff, rceb, rceb_size);
-               /* try more tables that might handle the same type */
-               if (size != -ENOENT)
-                       goto out;
-       }
-       dev_dbg(dev,
-               "event 0x%02x/%04x/%02x: no handlers available; RCEB %4ph\n",
-               (unsigned) rceb->bEventType,
-               (unsigned) le16_to_cpu(rceb->wEvent),
-               (unsigned) rceb->bEventContext,
-               rceb);
-       size = -ENOENT;
-out:
-       read_unlock_irqrestore(&uwb_est_lock, flags);
-       return size;
-}
-EXPORT_SYMBOL_GPL(uwb_est_find_size);
diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c
deleted file mode 100644 (file)
index cd03b7f..0000000
+++ /dev/null
@@ -1,929 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * WUSB Host Wire Adapter: Radio Control Interface (WUSB[8.6])
- * Radio Control command/event transport
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Initialize the Radio Control interface Driver.
- *
- * For each device probed, creates an 'struct hwarc' which contains
- * just the representation of the UWB Radio Controller, and the logic
- * for reading notifications and passing them to the UWB Core.
- *
- * So we initialize all of those, register the UWB Radio Controller
- * and setup the notification/event handle to pipe the notifications
- * to the UWB management Daemon.
- *
- * Command and event filtering.
- *
- * This is the driver for the Radio Control Interface described in WUSB
- * 1.0. The core UWB module assumes that all drivers are compliant to the
- * WHCI 0.95 specification. We thus create a filter that parses all
- * incoming messages from the (WUSB 1.0) device and manipulate them to
- * conform to the WHCI 0.95 specification. Similarly, outgoing messages
- * are parsed and manipulated to conform to the WUSB 1.0 compliant messages
- * that the device expects. Only a few messages are affected:
- * Affected events:
- *    UWB_RC_EVT_BEACON
- *    UWB_RC_EVT_BP_SLOT_CHANGE
- *    UWB_RC_EVT_DRP_AVAIL
- *    UWB_RC_EVT_DRP
- * Affected commands:
- *    UWB_RC_CMD_SCAN
- *    UWB_RC_CMD_SET_DRP_IE
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/usb/wusb.h>
-#include <linux/usb/wusb-wa.h>
-#include <linux/uwb.h>
-
-#include "uwb-internal.h"
-
-/* The device uses commands and events from the WHCI specification, although
- * reporting itself as WUSB compliant. */
-#define WUSB_QUIRK_WHCI_CMD_EVT                0x01
-
-/**
- * Descriptor for an instance of the UWB Radio Control Driver that
- * attaches to the RCI interface of the Host Wired Adapter.
- *
- * Unless there is a lock specific to the 'data members', all access
- * is protected by uwb_rc->mutex.
- *
- * The NEEP (Notification/Event EndPoint) URB (@neep_urb) writes to
- * @rd_buffer. Note there is no locking because it is perfectly (heh!)
- * serialized--probe() submits an URB, callback is called, processes
- * the data (synchronously), submits another URB, and so on. There is
- * no concurrent access to the buffer.
- */
-struct hwarc {
-       struct usb_device *usb_dev;
-       struct usb_interface *usb_iface;
-       struct uwb_rc *uwb_rc;          /* UWB host controller */
-       struct urb *neep_urb;           /* Notification endpoint handling */
-       struct edc neep_edc;
-       void *rd_buffer;                /* NEEP read buffer */
-};
-
-
-/* Beacon received notification (WUSB 1.0 [8.6.3.2]) */
-struct uwb_rc_evt_beacon_WUSB_0100 {
-       struct uwb_rceb rceb;
-       u8      bChannelNumber;
-       __le16  wBPSTOffset;
-       u8      bLQI;
-       u8      bRSSI;
-       __le16  wBeaconInfoLength;
-       u8      BeaconInfo[];
-} __attribute__((packed));
-
-/**
- * Filter WUSB 1.0 BEACON RCV notification to be WHCI 0.95
- *
- * @header: the incoming event
- * @buf_size: size of buffer containing incoming event
- * @new_size: size of event after filtering completed
- *
- * The WHCI 0.95 spec has a "Beacon Type" field. This value is unknown at
- * the time we receive the beacon from WUSB so we just set it to
- * UWB_RC_BEACON_TYPE_NEIGHBOR as a default.
- * The solution below allocates memory upon receipt of every beacon from a
- * WUSB device. This will deteriorate performance. What is the right way to
- * do this?
- */
-static
-int hwarc_filter_evt_beacon_WUSB_0100(struct uwb_rc *rc,
-                                     struct uwb_rceb **header,
-                                     const size_t buf_size,
-                                     size_t *new_size)
-{
-       struct uwb_rc_evt_beacon_WUSB_0100 *be;
-       struct uwb_rc_evt_beacon *newbe;
-       size_t bytes_left, ielength;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       be = container_of(*header, struct uwb_rc_evt_beacon_WUSB_0100, rceb);
-       bytes_left = buf_size;
-       if (bytes_left < sizeof(*be)) {
-               dev_err(dev, "Beacon Received Notification: Not enough data "
-                       "to decode for filtering (%zu vs %zu bytes needed)\n",
-                       bytes_left, sizeof(*be));
-               return -EINVAL;
-       }
-       bytes_left -= sizeof(*be);
-       ielength = le16_to_cpu(be->wBeaconInfoLength);
-       if (bytes_left < ielength) {
-               dev_err(dev, "Beacon Received Notification: Not enough data "
-                       "to decode IEs (%zu vs %zu bytes needed)\n",
-                       bytes_left, ielength);
-               return -EINVAL;
-       }
-       newbe = kzalloc(sizeof(*newbe) + ielength, GFP_ATOMIC);
-       if (newbe == NULL)
-               return -ENOMEM;
-       newbe->rceb = be->rceb;
-       newbe->bChannelNumber = be->bChannelNumber;
-       newbe->bBeaconType = UWB_RC_BEACON_TYPE_NEIGHBOR;
-       newbe->wBPSTOffset = be->wBPSTOffset;
-       newbe->bLQI = be->bLQI;
-       newbe->bRSSI = be->bRSSI;
-       newbe->wBeaconInfoLength = be->wBeaconInfoLength;
-       memcpy(newbe->BeaconInfo, be->BeaconInfo, ielength);
-       *header = &newbe->rceb;
-       *new_size = sizeof(*newbe) + ielength;
-       return 1;  /* calling function will free memory */
-}
-
-
-/* DRP Availability change notification (WUSB 1.0 [8.6.3.8]) */
-struct uwb_rc_evt_drp_avail_WUSB_0100 {
-       struct uwb_rceb rceb;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/**
- * Filter WUSB 1.0 DRP AVAILABILITY CHANGE notification to be WHCI 0.95
- *
- * @header: the incoming event
- * @buf_size: size of buffer containing incoming event
- * @new_size: size of event after filtering completed
- */
-static
-int hwarc_filter_evt_drp_avail_WUSB_0100(struct uwb_rc *rc,
-                                        struct uwb_rceb **header,
-                                        const size_t buf_size,
-                                        size_t *new_size)
-{
-       struct uwb_rc_evt_drp_avail_WUSB_0100 *da;
-       struct uwb_rc_evt_drp_avail *newda;
-       struct uwb_ie_hdr *ie_hdr;
-       size_t bytes_left, ielength;
-       struct device *dev = &rc->uwb_dev.dev;
-
-
-       da = container_of(*header, struct uwb_rc_evt_drp_avail_WUSB_0100, rceb);
-       bytes_left = buf_size;
-       if (bytes_left < sizeof(*da)) {
-               dev_err(dev, "Not enough data to decode DRP Avail "
-                       "Notification for filtering. Expected %zu, "
-                       "received %zu.\n", (size_t)sizeof(*da), bytes_left);
-               return -EINVAL;
-       }
-       bytes_left -= sizeof(*da);
-       ielength = le16_to_cpu(da->wIELength);
-       if (bytes_left < ielength) {
-               dev_err(dev, "DRP Avail Notification filter: IE length "
-                       "[%zu bytes] does not match actual length "
-                       "[%zu bytes].\n", ielength, bytes_left);
-               return -EINVAL;
-       }
-       if (ielength < sizeof(*ie_hdr)) {
-               dev_err(dev, "DRP Avail Notification filter: Not enough "
-                       "data to decode IE [%zu bytes, %zu needed]\n",
-                       ielength, sizeof(*ie_hdr));
-               return -EINVAL;
-       }
-       ie_hdr = (void *) da->IEData;
-       if (ie_hdr->length > 32) {
-               dev_err(dev, "DRP Availability Change event has unexpected "
-                       "length for filtering. Expected < 32 bytes, "
-                       "got %zu bytes.\n", (size_t)ie_hdr->length);
-               return -EINVAL;
-       }
-       newda = kzalloc(sizeof(*newda), GFP_ATOMIC);
-       if (newda == NULL)
-               return -ENOMEM;
-       newda->rceb = da->rceb;
-       memcpy(newda->bmp, (u8 *) ie_hdr + sizeof(*ie_hdr), ie_hdr->length);
-       *header = &newda->rceb;
-       *new_size = sizeof(*newda);
-       return 1; /* calling function will free memory */
-}
-
-
-/* DRP notification (WUSB 1.0 [8.6.3.9]) */
-struct uwb_rc_evt_drp_WUSB_0100 {
-       struct uwb_rceb rceb;
-       struct uwb_dev_addr wSrcAddr;
-       u8 bExplicit;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/**
- * Filter WUSB 1.0 DRP Notification to be WHCI 0.95
- *
- * @header: the incoming event
- * @buf_size: size of buffer containing incoming event
- * @new_size: size of event after filtering completed
- *
- * It is hard to manage DRP reservations without having a Reason code.
- * Unfortunately there is none in the WUSB spec. We just set the default to
- * DRP IE RECEIVED.
- * We do not currently use the bBeaconSlotNumber value, so we set this to
- * zero for now.
- */
-static
-int hwarc_filter_evt_drp_WUSB_0100(struct uwb_rc *rc,
-                                  struct uwb_rceb **header,
-                                  const size_t buf_size,
-                                  size_t *new_size)
-{
-       struct uwb_rc_evt_drp_WUSB_0100 *drpev;
-       struct uwb_rc_evt_drp *newdrpev;
-       size_t bytes_left, ielength;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       drpev = container_of(*header, struct uwb_rc_evt_drp_WUSB_0100, rceb);
-       bytes_left = buf_size;
-       if (bytes_left < sizeof(*drpev)) {
-               dev_err(dev, "Not enough data to decode DRP Notification "
-                       "for filtering. Expected %zu, received %zu.\n",
-                       (size_t)sizeof(*drpev), bytes_left);
-               return -EINVAL;
-       }
-       ielength = le16_to_cpu(drpev->wIELength);
-       bytes_left -= sizeof(*drpev);
-       if (bytes_left < ielength) {
-               dev_err(dev, "DRP Notification filter: header length [%zu "
-                       "bytes] does not match actual length [%zu "
-                       "bytes].\n", ielength, bytes_left);
-               return -EINVAL;
-       }
-       newdrpev = kzalloc(sizeof(*newdrpev) + ielength, GFP_ATOMIC);
-       if (newdrpev == NULL)
-               return -ENOMEM;
-       newdrpev->rceb = drpev->rceb;
-       newdrpev->src_addr = drpev->wSrcAddr;
-       newdrpev->reason = UWB_DRP_NOTIF_DRP_IE_RCVD;
-       newdrpev->beacon_slot_number = 0;
-       newdrpev->ie_length = drpev->wIELength;
-       memcpy(newdrpev->ie_data, drpev->IEData, ielength);
-       *header = &newdrpev->rceb;
-       *new_size = sizeof(*newdrpev) + ielength;
-       return 1; /* calling function will free memory */
-}
-
-
-/* Scan Command (WUSB 1.0 [8.6.2.5]) */
-struct uwb_rc_cmd_scan_WUSB_0100 {
-       struct uwb_rccb rccb;
-       u8 bChannelNumber;
-       u8 bScanState;
-} __attribute__((packed));
-
-/**
- * Filter WHCI 0.95 SCAN command to be WUSB 1.0 SCAN command
- *
- * @header:   command sent to device (compliant to WHCI 0.95)
- * @size:     size of command sent to device
- *
- * We only reduce the size by two bytes because the WUSB 1.0 scan command
- * does not have the last field (wStarttime). Also, make sure we don't send
- * the device an unexpected scan type.
- */
-static
-int hwarc_filter_cmd_scan_WUSB_0100(struct uwb_rc *rc,
-                                   struct uwb_rccb **header,
-                                   size_t *size)
-{
-       struct uwb_rc_cmd_scan *sc;
-
-       sc = container_of(*header, struct uwb_rc_cmd_scan, rccb);
-
-       if (sc->bScanState == UWB_SCAN_ONLY_STARTTIME)
-               sc->bScanState = UWB_SCAN_ONLY;
-       /* Don't send the last two bytes. */
-       *size -= 2;
-       return 0;
-}
-
-
-/* SET DRP IE command (WUSB 1.0 [8.6.2.7]) */
-struct uwb_rc_cmd_set_drp_ie_WUSB_0100 {
-       struct uwb_rccb rccb;
-       u8 bExplicit;
-       __le16 wIELength;
-       struct uwb_ie_drp IEData[];
-} __attribute__((packed));
-
-/**
- * Filter WHCI 0.95 SET DRP IE command to be WUSB 1.0 SET DRP IE command
- *
- * @header:   command sent to device (compliant to WHCI 0.95)
- * @size:     size of command sent to device
- *
- * WUSB has an extra bExplicit field - we assume always explicit
- * negotiation so this field is set. The command expected by the device is
- * thus larger than the one prepared by the driver so we need to
- * reallocate memory to accommodate this.
- * We trust the driver to send us the correct data so no checking is done
- * on incoming data - evn though it is variable length.
- */
-static
-int hwarc_filter_cmd_set_drp_ie_WUSB_0100(struct uwb_rc *rc,
-                                         struct uwb_rccb **header,
-                                         size_t *size)
-{
-       struct uwb_rc_cmd_set_drp_ie *orgcmd;
-       struct uwb_rc_cmd_set_drp_ie_WUSB_0100 *cmd;
-       size_t ielength;
-
-       orgcmd = container_of(*header, struct uwb_rc_cmd_set_drp_ie, rccb);
-       ielength = le16_to_cpu(orgcmd->wIELength);
-       cmd = kzalloc(sizeof(*cmd) + ielength, GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
-       cmd->rccb = orgcmd->rccb;
-       cmd->bExplicit = 0;
-       cmd->wIELength = orgcmd->wIELength;
-       memcpy(cmd->IEData, orgcmd->IEData, ielength);
-       *header = &cmd->rccb;
-       *size = sizeof(*cmd) + ielength;
-       return 1; /* calling function will free memory */
-}
-
-
-/**
- * Filter data from WHCI driver to WUSB device
- *
- * @header: WHCI 0.95 compliant command from driver
- * @size:   length of command
- *
- * The routine managing commands to the device (uwb_rc_cmd()) will call the
- * filtering function pointer (if it exists) before it passes any data to
- * the device. At this time the command has been formatted according to
- * WHCI 0.95 and is ready to be sent to the device.
- *
- * The filter function will be provided with the current command and its
- * length. The function will manipulate the command if necessary and
- * potentially reallocate memory for a command that needed more memory that
- * the given command. If new memory was created the function will return 1
- * to indicate to the calling function that the memory need to be freed
- * when not needed any more. The size will contain the new length of the
- * command.
- * If memory has not been allocated we rely on the original mechanisms to
- * free the memory of the command - even when we reduce the value of size.
- */
-static
-int hwarc_filter_cmd_WUSB_0100(struct uwb_rc *rc, struct uwb_rccb **header,
-                              size_t *size)
-{
-       int result;
-       struct uwb_rccb *rccb = *header;
-       int cmd = le16_to_cpu(rccb->wCommand);
-       switch (cmd) {
-       case UWB_RC_CMD_SCAN:
-               result = hwarc_filter_cmd_scan_WUSB_0100(rc, header, size);
-               break;
-       case UWB_RC_CMD_SET_DRP_IE:
-               result = hwarc_filter_cmd_set_drp_ie_WUSB_0100(rc, header, size);
-               break;
-       default:
-               result = -ENOANO;
-               break;
-       }
-       return result;
-}
-
-
-/**
- * Filter data from WHCI driver to WUSB device
- *
- * @header: WHCI 0.95 compliant command from driver
- * @size:   length of command
- *
- * Filter commands based on which protocol the device supports. The WUSB
- * errata should be the same as WHCI 0.95 so we do not filter that here -
- * only WUSB 1.0.
- */
-static
-int hwarc_filter_cmd(struct uwb_rc *rc, struct uwb_rccb **header,
-                    size_t *size)
-{
-       int result = -ENOANO;
-       if (rc->version == 0x0100)
-               result = hwarc_filter_cmd_WUSB_0100(rc, header, size);
-       return result;
-}
-
-
-/**
- * Compute return value as sum of incoming value and value at given offset
- *
- * @rceb:      event for which we compute the size, it contains a variable
- *            length field.
- * @core_size: size of the "non variable" part of the event
- * @offset:    place in event where the length of the variable part is stored
- * @buf_size: total length of buffer in which event arrived - we need to make
- *            sure we read the offset in memory that is still part of the event
- */
-static
-ssize_t hwarc_get_event_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
-                            size_t core_size, size_t offset,
-                            const size_t buf_size)
-{
-       ssize_t size = -ENOSPC;
-       const void *ptr = rceb;
-       size_t type_size = sizeof(__le16);
-       struct device *dev = &rc->uwb_dev.dev;
-
-       if (offset + type_size >= buf_size) {
-               dev_err(dev, "Not enough data to read extra size of event "
-                       "0x%02x/%04x/%02x, only got %zu bytes.\n",
-                       rceb->bEventType, le16_to_cpu(rceb->wEvent),
-                       rceb->bEventContext, buf_size);
-               goto out;
-       }
-       ptr += offset;
-       size = core_size + le16_to_cpu(*(__le16 *)ptr);
-out:
-       return size;
-}
-
-
-/* Beacon slot change notification (WUSB 1.0 [8.6.3.5]) */
-struct uwb_rc_evt_bp_slot_change_WUSB_0100 {
-       struct uwb_rceb rceb;
-       u8 bSlotNumber;
-} __attribute__((packed));
-
-
-/**
- * Filter data from WUSB device to WHCI driver
- *
- * @header:     incoming event
- * @buf_size:   size of buffer in which event arrived
- * @_event_size: actual size of event in the buffer
- * @new_size:   size of event after filtered
- *
- * We don't know how the buffer is constructed - there may be more than one
- * event in it so buffer length does not determine event length. We first
- * determine the expected size of the incoming event. This value is passed
- * back only if the actual filtering succeeded (so we know the computed
- * expected size is correct). This value will be zero if
- * the event did not need any filtering.
- *
- * WHCI interprets the BP Slot Change event's data differently than
- * WUSB. The event sizes are exactly the same. The data field
- * indicates the new beacon slot in which a RC is transmitting its
- * beacon. The maximum value of this is 96 (wMacBPLength ECMA-368
- * 17.16 (Table 117)). We thus know that the WUSB value will not set
- * the bit bNoSlot, so we don't really do anything (placeholder).
- */
-static
-int hwarc_filter_event_WUSB_0100(struct uwb_rc *rc, struct uwb_rceb **header,
-                                const size_t buf_size, size_t *_real_size,
-                                size_t *_new_size)
-{
-       int result = -ENOANO;
-       struct uwb_rceb *rceb = *header;
-       int event = le16_to_cpu(rceb->wEvent);
-       ssize_t event_size;
-       size_t core_size, offset;
-
-       if (rceb->bEventType != UWB_RC_CET_GENERAL)
-               goto out;
-       switch (event) {
-       case UWB_RC_EVT_BEACON:
-               core_size = sizeof(struct uwb_rc_evt_beacon_WUSB_0100);
-               offset = offsetof(struct uwb_rc_evt_beacon_WUSB_0100,
-                                 wBeaconInfoLength);
-               event_size = hwarc_get_event_size(rc, rceb, core_size,
-                                                 offset, buf_size);
-               if (event_size < 0)
-                       goto out;
-               *_real_size = event_size;
-               result = hwarc_filter_evt_beacon_WUSB_0100(rc, header,
-                                                          buf_size, _new_size);
-               break;
-       case UWB_RC_EVT_BP_SLOT_CHANGE:
-               *_new_size = *_real_size =
-                       sizeof(struct uwb_rc_evt_bp_slot_change_WUSB_0100);
-               result = 0;
-               break;
-
-       case UWB_RC_EVT_DRP_AVAIL:
-               core_size = sizeof(struct uwb_rc_evt_drp_avail_WUSB_0100);
-               offset = offsetof(struct uwb_rc_evt_drp_avail_WUSB_0100,
-                                 wIELength);
-               event_size = hwarc_get_event_size(rc, rceb, core_size,
-                                                 offset, buf_size);
-               if (event_size < 0)
-                       goto out;
-               *_real_size = event_size;
-               result = hwarc_filter_evt_drp_avail_WUSB_0100(
-                       rc, header, buf_size, _new_size);
-               break;
-
-       case UWB_RC_EVT_DRP:
-               core_size = sizeof(struct uwb_rc_evt_drp_WUSB_0100);
-               offset = offsetof(struct uwb_rc_evt_drp_WUSB_0100, wIELength);
-               event_size = hwarc_get_event_size(rc, rceb, core_size,
-                                                 offset, buf_size);
-               if (event_size < 0)
-                       goto out;
-               *_real_size = event_size;
-               result = hwarc_filter_evt_drp_WUSB_0100(rc, header,
-                                                       buf_size, _new_size);
-               break;
-
-       default:
-               break;
-       }
-out:
-       return result;
-}
-
-/**
- * Filter data from WUSB device to WHCI driver
- *
- * @header:     incoming event
- * @buf_size:   size of buffer in which event arrived
- * @_event_size: actual size of event in the buffer
- * @_new_size:  size of event after filtered
- *
- * Filter events based on which protocol the device supports. The WUSB
- * errata should be the same as WHCI 0.95 so we do not filter that here -
- * only WUSB 1.0.
- *
- * If we don't handle it, we return -ENOANO (why the weird error code?
- * well, so if I get it, I can pinpoint in the code that raised
- * it...after all, not too many places use the higher error codes).
- */
-static
-int hwarc_filter_event(struct uwb_rc *rc, struct uwb_rceb **header,
-                      const size_t buf_size, size_t *_real_size,
-                      size_t *_new_size)
-{
-       int result = -ENOANO;
-       if (rc->version == 0x0100)
-               result =  hwarc_filter_event_WUSB_0100(
-                       rc, header, buf_size, _real_size, _new_size);
-       return result;
-}
-
-
-/**
- * Execute an UWB RC command on HWA
- *
- * @rc:              Instance of a Radio Controller that is a HWA
- * @cmd:      Buffer containing the RCCB and payload to execute
- * @cmd_size: Size of the command buffer.
- *
- * NOTE: rc's mutex has to be locked
- */
-static
-int hwarc_cmd(struct uwb_rc *uwb_rc, const struct uwb_rccb *cmd, size_t cmd_size)
-{
-       struct hwarc *hwarc = uwb_rc->priv;
-       return usb_control_msg(
-               hwarc->usb_dev, usb_sndctrlpipe(hwarc->usb_dev, 0),
-               WA_EXEC_RC_CMD, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0, hwarc->usb_iface->cur_altsetting->desc.bInterfaceNumber,
-               (void *) cmd, cmd_size, 100 /* FIXME: this is totally arbitrary */);
-}
-
-static
-int hwarc_reset(struct uwb_rc *uwb_rc)
-{
-       struct hwarc *hwarc = uwb_rc->priv;
-       int result;
-
-       /* device lock must be held when calling usb_reset_device. */
-       result = usb_lock_device_for_reset(hwarc->usb_dev, NULL);
-       if (result >= 0) {
-               result = usb_reset_device(hwarc->usb_dev);
-               usb_unlock_device(hwarc->usb_dev);
-       }
-
-       return result;
-}
-
-/**
- * Callback for the notification and event endpoint
- *
- * Check's that everything is fine and then passes the read data to
- * the notification/event handling mechanism (neh).
- */
-static
-void hwarc_neep_cb(struct urb *urb)
-{
-       struct hwarc *hwarc = urb->context;
-       struct usb_interface *usb_iface = hwarc->usb_iface;
-       struct device *dev = &usb_iface->dev;
-       int result;
-
-       switch (result = urb->status) {
-       case 0:
-               uwb_rc_neh_grok(hwarc->uwb_rc, urb->transfer_buffer,
-                               urb->actual_length);
-               break;
-       case -ECONNRESET:       /* Not an error, but a controlled situation; */
-       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
-               goto out;
-       case -ESHUTDOWN:        /* going away! */
-               goto out;
-       default:                /* On general errors, retry unless it gets ugly */
-               if (edc_inc(&hwarc->neep_edc, EDC_MAX_ERRORS,
-                           EDC_ERROR_TIMEFRAME))
-                       goto error_exceeded;
-               dev_err(dev, "NEEP: URB error %d\n", urb->status);
-       }
-       result = usb_submit_urb(urb, GFP_ATOMIC);
-       if (result < 0 && result != -ENODEV && result != -EPERM) {
-               /* ignoring unrecoverable errors */
-               dev_err(dev, "NEEP: Can't resubmit URB (%d) resetting device\n",
-                       result);
-               goto error;
-       }
-out:
-       return;
-
-error_exceeded:
-       dev_err(dev, "NEEP: URB max acceptable errors "
-               "exceeded, resetting device\n");
-error:
-       uwb_rc_neh_error(hwarc->uwb_rc, result);
-       uwb_rc_reset_all(hwarc->uwb_rc);
-       return;
-}
-
-static void hwarc_init(struct hwarc *hwarc)
-{
-       edc_init(&hwarc->neep_edc);
-}
-
-/**
- * Initialize the notification/event endpoint stuff
- *
- * Note this is effectively a parallel thread; it knows that
- * hwarc->uwb_rc always exists because the existence of a 'hwarc'
- * means that there is a reverence on the hwarc->uwb_rc (see
- * _probe()), and thus _neep_cb() can execute safely.
- */
-static int hwarc_neep_init(struct uwb_rc *rc)
-{
-       struct hwarc *hwarc = rc->priv;
-       struct usb_interface *iface = hwarc->usb_iface;
-       struct usb_device *usb_dev = interface_to_usbdev(iface);
-       struct device *dev = &iface->dev;
-       int result;
-       struct usb_endpoint_descriptor *epd;
-
-       epd = &iface->cur_altsetting->endpoint[0].desc;
-       hwarc->rd_buffer = (void *) __get_free_page(GFP_KERNEL);
-       if (hwarc->rd_buffer == NULL) {
-               dev_err(dev, "Unable to allocate notification's read buffer\n");
-               goto error_rd_buffer;
-       }
-       hwarc->neep_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (hwarc->neep_urb == NULL)
-               goto error_urb_alloc;
-       usb_fill_int_urb(hwarc->neep_urb, usb_dev,
-                        usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
-                        hwarc->rd_buffer, PAGE_SIZE,
-                        hwarc_neep_cb, hwarc, epd->bInterval);
-       result = usb_submit_urb(hwarc->neep_urb, GFP_ATOMIC);
-       if (result < 0) {
-               dev_err(dev, "Cannot submit notification URB: %d\n", result);
-               goto error_neep_submit;
-       }
-       return 0;
-
-error_neep_submit:
-       usb_free_urb(hwarc->neep_urb);
-       hwarc->neep_urb = NULL;
-error_urb_alloc:
-       free_page((unsigned long)hwarc->rd_buffer);
-       hwarc->rd_buffer = NULL;
-error_rd_buffer:
-       return -ENOMEM;
-}
-
-
-/** Clean up all the notification endpoint resources */
-static void hwarc_neep_release(struct uwb_rc *rc)
-{
-       struct hwarc *hwarc = rc->priv;
-
-       usb_kill_urb(hwarc->neep_urb);
-       usb_free_urb(hwarc->neep_urb);
-       hwarc->neep_urb = NULL;
-
-       free_page((unsigned long)hwarc->rd_buffer);
-       hwarc->rd_buffer = NULL;
-}
-
-/**
- * Get the version from class-specific descriptor
- *
- * NOTE: this descriptor comes with the big bundled configuration
- *      descriptor that includes the interfaces' and endpoints', so
- *      we just look for it in the cached copy kept by the USB stack.
- *
- * NOTE2: We convert LE fields to CPU order.
- */
-static int hwarc_get_version(struct uwb_rc *rc)
-{
-       int result;
-
-       struct hwarc *hwarc = rc->priv;
-       struct uwb_rc_control_intf_class_desc *descr;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct usb_device *usb_dev = hwarc->usb_dev;
-       char *itr;
-       struct usb_descriptor_header *hdr;
-       size_t itr_size, actconfig_idx;
-       u16 version;
-
-       actconfig_idx = (usb_dev->actconfig - usb_dev->config) /
-               sizeof(usb_dev->config[0]);
-       itr = usb_dev->rawdescriptors[actconfig_idx];
-       itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength);
-       while (itr_size >= sizeof(*hdr)) {
-               hdr = (struct usb_descriptor_header *) itr;
-               dev_dbg(dev, "Extra device descriptor: "
-                       "type %02x/%u bytes @ %zu (%zu left)\n",
-                       hdr->bDescriptorType, hdr->bLength,
-                       (itr - usb_dev->rawdescriptors[actconfig_idx]),
-                       itr_size);
-               if (hdr->bDescriptorType == USB_DT_CS_RADIO_CONTROL)
-                       goto found;
-               itr += hdr->bLength;
-               itr_size -= hdr->bLength;
-       }
-       dev_err(dev, "cannot find Radio Control Interface Class descriptor\n");
-       return -ENODEV;
-
-found:
-       result = -EINVAL;
-       if (hdr->bLength > itr_size) {  /* is it available? */
-               dev_err(dev, "incomplete Radio Control Interface Class "
-                       "descriptor (%zu bytes left, %u needed)\n",
-                       itr_size, hdr->bLength);
-               goto error;
-       }
-       if (hdr->bLength < sizeof(*descr)) {
-               dev_err(dev, "short Radio Control Interface Class "
-                       "descriptor\n");
-               goto error;
-       }
-       descr = (struct uwb_rc_control_intf_class_desc *) hdr;
-       /* Make LE fields CPU order */
-       version = __le16_to_cpu(descr->bcdRCIVersion);
-       if (version != 0x0100) {
-               dev_err(dev, "Device reports protocol version 0x%04x. We "
-                       "do not support that. \n", version);
-               result = -EINVAL;
-               goto error;
-       }
-       rc->version = version;
-       dev_dbg(dev, "Device supports WUSB protocol version 0x%04x \n", rc->version);
-       result = 0;
-error:
-       return result;
-}
-
-/*
- * By creating a 'uwb_rc', we have a reference on it -- that reference
- * is the one we drop when we disconnect.
- *
- * No need to switch altsettings; according to WUSB1.0[8.6.1.1], there
- * is only one altsetting allowed.
- */
-static int hwarc_probe(struct usb_interface *iface,
-                      const struct usb_device_id *id)
-{
-       int result;
-       struct uwb_rc *uwb_rc;
-       struct hwarc *hwarc;
-       struct device *dev = &iface->dev;
-
-       if (iface->cur_altsetting->desc.bNumEndpoints < 1)
-               return -ENODEV;
-       if (!usb_endpoint_xfer_int(&iface->cur_altsetting->endpoint[0].desc))
-               return -ENODEV;
-
-       result = -ENOMEM;
-       uwb_rc = uwb_rc_alloc();
-       if (uwb_rc == NULL) {
-               dev_err(dev, "unable to allocate RC instance\n");
-               goto error_rc_alloc;
-       }
-       hwarc = kzalloc(sizeof(*hwarc), GFP_KERNEL);
-       if (hwarc == NULL) {
-               dev_err(dev, "unable to allocate HWA RC instance\n");
-               goto error_alloc;
-       }
-       hwarc_init(hwarc);
-       hwarc->usb_dev = usb_get_dev(interface_to_usbdev(iface));
-       hwarc->usb_iface = usb_get_intf(iface);
-       hwarc->uwb_rc = uwb_rc;
-
-       uwb_rc->owner = THIS_MODULE;
-       uwb_rc->start = hwarc_neep_init;
-       uwb_rc->stop  = hwarc_neep_release;
-       uwb_rc->cmd   = hwarc_cmd;
-       uwb_rc->reset = hwarc_reset;
-       if (id->driver_info & WUSB_QUIRK_WHCI_CMD_EVT) {
-               uwb_rc->filter_cmd   = NULL;
-               uwb_rc->filter_event = NULL;
-       } else {
-               uwb_rc->filter_cmd   = hwarc_filter_cmd;
-               uwb_rc->filter_event = hwarc_filter_event;
-       }
-
-       result = uwb_rc_add(uwb_rc, dev, hwarc);
-       if (result < 0)
-               goto error_rc_add;
-       result = hwarc_get_version(uwb_rc);
-       if (result < 0) {
-               dev_err(dev, "cannot retrieve version of RC \n");
-               goto error_get_version;
-       }
-       usb_set_intfdata(iface, hwarc);
-       return 0;
-
-error_get_version:
-       uwb_rc_rm(uwb_rc);
-error_rc_add:
-       usb_put_intf(iface);
-       usb_put_dev(hwarc->usb_dev);
-       kfree(hwarc);
-error_alloc:
-       uwb_rc_put(uwb_rc);
-error_rc_alloc:
-       return result;
-}
-
-static void hwarc_disconnect(struct usb_interface *iface)
-{
-       struct hwarc *hwarc = usb_get_intfdata(iface);
-       struct uwb_rc *uwb_rc = hwarc->uwb_rc;
-
-       usb_set_intfdata(hwarc->usb_iface, NULL);
-       uwb_rc_rm(uwb_rc);
-       usb_put_intf(hwarc->usb_iface);
-       usb_put_dev(hwarc->usb_dev);
-       kfree(hwarc);
-       uwb_rc_put(uwb_rc);     /* when creating the device, refcount = 1 */
-}
-
-static int hwarc_pre_reset(struct usb_interface *iface)
-{
-       struct hwarc *hwarc = usb_get_intfdata(iface);
-       struct uwb_rc *uwb_rc = hwarc->uwb_rc;
-
-       uwb_rc_pre_reset(uwb_rc);
-       return 0;
-}
-
-static int hwarc_post_reset(struct usb_interface *iface)
-{
-       struct hwarc *hwarc = usb_get_intfdata(iface);
-       struct uwb_rc *uwb_rc = hwarc->uwb_rc;
-
-       return uwb_rc_post_reset(uwb_rc);
-}
-
-/** USB device ID's that we handle */
-static const struct usb_device_id hwarc_id_table[] = {
-       /* D-Link DUB-1210 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3d02, 0xe0, 0x01, 0x02),
-         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
-       /* Intel i1480 (using firmware 1.3PA2-20070828) */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x8086, 0x0c3b, 0xe0, 0x01, 0x02),
-         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
-       /* Alereon 5310 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x01, 0x02),
-         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
-       /* Alereon 5611 */
-       { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x01, 0x02),
-         .driver_info = WUSB_QUIRK_WHCI_CMD_EVT },
-       /* Generic match for the Radio Control interface */
-       { USB_INTERFACE_INFO(0xe0, 0x01, 0x02), },
-       { },
-};
-MODULE_DEVICE_TABLE(usb, hwarc_id_table);
-
-static struct usb_driver hwarc_driver = {
-       .name =         "hwa-rc",
-       .id_table =     hwarc_id_table,
-       .probe =        hwarc_probe,
-       .disconnect =   hwarc_disconnect,
-       .pre_reset =    hwarc_pre_reset,
-       .post_reset =   hwarc_post_reset,
-};
-
-module_usb_driver(hwarc_driver);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Host Wireless Adapter Radio Control Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/i1480/Makefile b/drivers/uwb/i1480/Makefile
deleted file mode 100644 (file)
index d26fb9b..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_UWB_I1480U)       += dfu/ i1480-est.o
diff --git a/drivers/uwb/i1480/dfu/Makefile b/drivers/uwb/i1480/dfu/Makefile
deleted file mode 100644 (file)
index 4739fda..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# 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
-
-
diff --git a/drivers/uwb/i1480/dfu/dfu.c b/drivers/uwb/i1480/dfu/dfu.c
deleted file mode 100644 (file)
index ec1af85..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-// 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/uwb.h>
-#include <linux/random.h>
-#include <linux/export.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);
diff --git a/drivers/uwb/i1480/dfu/i1480-dfu.h b/drivers/uwb/i1480/dfu/i1480-dfu.h
deleted file mode 100644 (file)
index 9dd567d..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/* 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/uwb/spec.h>
-#include <linux/types.h>
-#include <linux/completion.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__ */
diff --git a/drivers/uwb/i1480/dfu/mac.c b/drivers/uwb/i1480/dfu/mac.c
deleted file mode 100644 (file)
index ddc224f..0000000
+++ /dev/null
@@ -1,496 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Wireless UWB Link 1480
- * MAC Firmware upload implementation
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Implementation of the code for parsing the firmware file (extract
- * the headers and binary code chunks) in the fw_*() functions. The
- * code to upload pre and mac firmwares is the same, so it uses a
- * common entry point in __mac_fw_upload(), which uses the i1480
- * function pointers to push the firmware to the device.
- */
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <linux/uwb.h>
-#include "i1480-dfu.h"
-
-/*
- * Descriptor for a continuous segment of MAC fw data
- */
-struct fw_hdr {
-       unsigned long address;
-       size_t length;
-       const u32 *bin;
-       struct fw_hdr *next;
-};
-
-
-/* Free a chain of firmware headers */
-static
-void fw_hdrs_free(struct fw_hdr *hdr)
-{
-       struct fw_hdr *next;
-
-       while (hdr) {
-               next = hdr->next;
-               kfree(hdr);
-               hdr = next;
-       }
-}
-
-
-/* Fill a firmware header descriptor from a memory buffer */
-static
-int fw_hdr_load(struct i1480 *i1480, struct fw_hdr *hdr, unsigned hdr_cnt,
-               const char *_data, const u32 *data_itr, const u32 *data_top)
-{
-       size_t hdr_offset =  (const char *) data_itr - _data;
-       size_t remaining_size = (void *) data_top - (void *) data_itr;
-       if (data_itr + 2 > data_top) {
-               dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in header at "
-                      "offset %zu, limit %zu\n",
-                      hdr_cnt, hdr_offset,
-                      (const char *) data_itr + 2 - _data,
-                      (const char *) data_top - _data);
-               return -EINVAL;
-       }
-       hdr->next = NULL;
-       hdr->address = le32_to_cpu(*data_itr++);
-       hdr->length = le32_to_cpu(*data_itr++);
-       hdr->bin = data_itr;
-       if (hdr->length > remaining_size) {
-               dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in data; "
-                      "chunk too long (%zu bytes), only %zu left\n",
-                      hdr_cnt, hdr_offset, hdr->length, remaining_size);
-               return -EINVAL;
-       }
-       return 0;
-}
-
-
-/**
- * Get a buffer where the firmware is supposed to be and create a
- * chain of headers linking them together.
- *
- * @phdr: where to place the pointer to the first header (headers link
- *        to the next via the @hdr->next ptr); need to free the whole
- *        chain when done.
- *
- * @_data: Pointer to the data buffer.
- *
- * @_data_size: Size of the data buffer (bytes); data size has to be a
- *              multiple of 4. Function will fail if not.
- *
- * Goes over the whole binary blob; reads the first chunk and creates
- * a fw hdr from it (which points to where the data is in @_data and
- * the length of the chunk); then goes on to the next chunk until
- * done. Each header is linked to the next.
- */
-static
-int fw_hdrs_load(struct i1480 *i1480, struct fw_hdr **phdr,
-                const char *_data, size_t data_size)
-{
-       int result;
-       unsigned hdr_cnt = 0;
-       u32 *data = (u32 *) _data, *data_itr, *data_top;
-       struct fw_hdr *hdr, **prev_hdr = phdr;
-
-       result = -EINVAL;
-       /* Check size is ok and pointer is aligned */
-       if (data_size % sizeof(u32) != 0)
-               goto error;
-       if ((unsigned long) _data % sizeof(u16) != 0)
-               goto error;
-       *phdr = NULL;
-       data_itr = data;
-       data_top = (u32 *) (_data + data_size);
-       while (data_itr < data_top) {
-               result = -ENOMEM;
-               hdr = kmalloc(sizeof(*hdr), GFP_KERNEL);
-               if (hdr == NULL) {
-                       dev_err(i1480->dev, "Cannot allocate fw header "
-                              "for chunk #%u\n", hdr_cnt);
-                       goto error_alloc;
-               }
-               result = fw_hdr_load(i1480, hdr, hdr_cnt,
-                                    _data, data_itr, data_top);
-               if (result < 0)
-                       goto error_load;
-               data_itr += 2 + hdr->length;
-               *prev_hdr = hdr;
-               prev_hdr = &hdr->next;
-               hdr_cnt++;
-       };
-       *prev_hdr = NULL;
-       return 0;
-
-error_load:
-       kfree(hdr);
-error_alloc:
-       fw_hdrs_free(*phdr);
-error:
-       return result;
-}
-
-
-/**
- * Compares a chunk of fw with one in the devices's memory
- *
- * @i1480:     Device instance
- * @hdr:     Pointer to the firmware chunk
- * @returns: 0 if equal, < 0 errno on error. If > 0, it is the offset
- *           where the difference was found (plus one).
- *
- * Kind of dirty and simplistic, but does the trick in both the PCI
- * and USB version. We do a quick[er] memcmp(), and if it fails, we do
- * a byte-by-byte to find the offset.
- */
-static
-ssize_t i1480_fw_cmp(struct i1480 *i1480, struct fw_hdr *hdr)
-{
-       ssize_t result = 0;
-       u32 src_itr = 0, cnt;
-       size_t size = hdr->length*sizeof(hdr->bin[0]);
-       size_t chunk_size;
-       u8 *bin = (u8 *) hdr->bin;
-
-       while (size > 0) {
-               chunk_size = size < i1480->buf_size ? size : i1480->buf_size;
-               result = i1480->read(i1480, hdr->address + src_itr, chunk_size);
-               if (result < 0) {
-                       dev_err(i1480->dev, "error reading for verification: "
-                               "%zd\n", result);
-                       goto error;
-               }
-               if (memcmp(i1480->cmd_buf, bin + src_itr, result)) {
-                       u8 *buf = i1480->cmd_buf;
-                       for (cnt = 0; cnt < result; cnt++)
-                               if (bin[src_itr + cnt] != buf[cnt]) {
-                                       dev_err(i1480->dev, "byte failed at "
-                                               "src_itr %u cnt %u [0x%02x "
-                                               "vs 0x%02x]\n", src_itr, cnt,
-                                               bin[src_itr + cnt], buf[cnt]);
-                                       result = src_itr + cnt + 1;
-                                       goto cmp_failed;
-                               }
-               }
-               src_itr += result;
-               size -= result;
-       }
-       result = 0;
-error:
-cmp_failed:
-       return result;
-}
-
-
-/**
- * Writes firmware headers to the device.
- *
- * @prd:     PRD instance
- * @hdr:     Processed firmware
- * @returns: 0 if ok, < 0 errno on error.
- */
-static
-int mac_fw_hdrs_push(struct i1480 *i1480, struct fw_hdr *hdr,
-                    const char *fw_name, const char *fw_tag)
-{
-       struct device *dev = i1480->dev;
-       ssize_t result = 0;
-       struct fw_hdr *hdr_itr;
-       int verif_retry_count;
-
-       /* Now, header by header, push them to the hw */
-       for (hdr_itr = hdr; hdr_itr != NULL; hdr_itr = hdr_itr->next) {
-               verif_retry_count = 0;
-retry:
-               dev_dbg(dev, "fw chunk (%zu @ 0x%08lx)\n",
-                       hdr_itr->length * sizeof(hdr_itr->bin[0]),
-                       hdr_itr->address);
-               result = i1480->write(i1480, hdr_itr->address, hdr_itr->bin,
-                                   hdr_itr->length*sizeof(hdr_itr->bin[0]));
-               if (result < 0) {
-                       dev_err(dev, "%s fw '%s': write failed (%zuB @ 0x%lx):"
-                               " %zd\n", fw_tag, fw_name,
-                               hdr_itr->length * sizeof(hdr_itr->bin[0]),
-                               hdr_itr->address, result);
-                       break;
-               }
-               result = i1480_fw_cmp(i1480, hdr_itr);
-               if (result < 0) {
-                       dev_err(dev, "%s fw '%s': verification read "
-                               "failed (%zuB @ 0x%lx): %zd\n",
-                               fw_tag, fw_name,
-                               hdr_itr->length * sizeof(hdr_itr->bin[0]),
-                               hdr_itr->address, result);
-                       break;
-               }
-               if (result > 0) {       /* Offset where it failed + 1 */
-                       result--;
-                       dev_err(dev, "%s fw '%s': WARNING: verification "
-                               "failed at 0x%lx: retrying\n",
-                               fw_tag, fw_name, hdr_itr->address + result);
-                       if (++verif_retry_count < 3)
-                               goto retry;     /* write this block again! */
-                       dev_err(dev, "%s fw '%s': verification failed at 0x%lx: "
-                               "tried %d times\n", fw_tag, fw_name,
-                               hdr_itr->address + result, verif_retry_count);
-                       result = -EINVAL;
-                       break;
-               }
-       }
-       return result;
-}
-
-
-/** Puts the device in firmware upload mode.*/
-static
-int mac_fw_upload_enable(struct i1480 *i1480)
-{
-       int result;
-       u32 reg = 0x800000c0;
-       u32 *buffer = (u32 *)i1480->cmd_buf;
-
-       if (i1480->hw_rev > 1)
-               reg = 0x8000d0d4;
-       result = i1480->read(i1480, reg, sizeof(u32));
-       if (result < 0)
-               goto error_cmd;
-       *buffer &= ~i1480_FW_UPLOAD_MODE_MASK;
-       result = i1480->write(i1480, reg, buffer, sizeof(u32));
-       if (result < 0)
-               goto error_cmd;
-       return 0;
-error_cmd:
-       dev_err(i1480->dev, "can't enable fw upload mode: %d\n", result);
-       return result;
-}
-
-
-/** Gets the device out of firmware upload mode. */
-static
-int mac_fw_upload_disable(struct i1480 *i1480)
-{
-       int result;
-       u32 reg = 0x800000c0;
-       u32 *buffer = (u32 *)i1480->cmd_buf;
-
-       if (i1480->hw_rev > 1)
-               reg = 0x8000d0d4;
-       result = i1480->read(i1480, reg, sizeof(u32));
-       if (result < 0)
-               goto error_cmd;
-       *buffer |= i1480_FW_UPLOAD_MODE_MASK;
-       result = i1480->write(i1480, reg, buffer, sizeof(u32));
-       if (result < 0)
-               goto error_cmd;
-       return 0;
-error_cmd:
-       dev_err(i1480->dev, "can't disable fw upload mode: %d\n", result);
-       return result;
-}
-
-
-
-/**
- * Generic function for uploading a MAC firmware.
- *
- * @i1480:     Device instance
- * @fw_name: Name of firmware file to upload.
- * @fw_tag:  Name of the firmware type (for messages)
- *           [eg: MAC, PRE]
- * @do_wait: Wait for device to emit initialization done message (0
- *           for PRE fws, 1 for MAC fws).
- * @returns: 0 if ok, < 0 errno on error.
- */
-static
-int __mac_fw_upload(struct i1480 *i1480, const char *fw_name,
-                   const char *fw_tag)
-{
-       int result;
-       const struct firmware *fw;
-       struct fw_hdr *fw_hdrs;
-
-       result = request_firmware(&fw, fw_name, i1480->dev);
-       if (result < 0) /* Up to caller to complain on -ENOENT */
-               goto out;
-       result = fw_hdrs_load(i1480, &fw_hdrs, fw->data, fw->size);
-       if (result < 0) {
-               dev_err(i1480->dev, "%s fw '%s': failed to parse firmware "
-                       "file: %d\n", fw_tag, fw_name, result);
-               goto out_release;
-       }
-       result = mac_fw_upload_enable(i1480);
-       if (result < 0)
-               goto out_hdrs_release;
-       result = mac_fw_hdrs_push(i1480, fw_hdrs, fw_name, fw_tag);
-       mac_fw_upload_disable(i1480);
-out_hdrs_release:
-       if (result >= 0)
-               dev_info(i1480->dev, "%s fw '%s': uploaded\n", fw_tag, fw_name);
-       else
-               dev_err(i1480->dev, "%s fw '%s': failed to upload (%d), "
-                       "power cycle device\n", fw_tag, fw_name, result);
-       fw_hdrs_free(fw_hdrs);
-out_release:
-       release_firmware(fw);
-out:
-       return result;
-}
-
-
-/**
- * Upload a pre-PHY firmware
- *
- */
-int i1480_pre_fw_upload(struct i1480 *i1480)
-{
-       int result;
-       result = __mac_fw_upload(i1480, i1480->pre_fw_name, "PRE");
-       if (result == 0)
-               msleep(400);
-       return result;
-}
-
-
-/**
- * Reset a the MAC and PHY
- *
- * @i1480:     Device's instance
- * @returns: 0 if ok, < 0 errno code on error
- *
- * We put the command on kmalloc'ed memory as some arches cannot do
- * USB from the stack. The reply event is copied from an stage buffer,
- * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
- *
- * We issue the reset to make sure the UWB controller reinits the PHY;
- * this way we can now if the PHY init went ok.
- */
-static
-int i1480_cmd_reset(struct i1480 *i1480)
-{
-       int result;
-       struct uwb_rccb *cmd = (void *) i1480->cmd_buf;
-       struct i1480_evt_reset {
-               struct uwb_rceb rceb;
-               u8 bResultCode;
-       } __attribute__((packed)) *reply = (void *) i1480->evt_buf;
-
-       result = -ENOMEM;
-       cmd->bCommandType = UWB_RC_CET_GENERAL;
-       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET);
-       reply->rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply->rceb.wEvent = UWB_RC_CMD_RESET;
-       result = i1480_cmd(i1480, "RESET", sizeof(*cmd), sizeof(*reply));
-       if (result < 0)
-               goto out;
-       if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(i1480->dev, "RESET: command execution failed: %u\n",
-                       reply->bResultCode);
-               result = -EIO;
-       }
-out:
-       return result;
-
-}
-
-
-/* Wait for the MAC FW to start running */
-static
-int i1480_fw_is_running_q(struct i1480 *i1480)
-{
-       int cnt = 0;
-       int result;
-       u32 *val = (u32 *) i1480->cmd_buf;
-
-       for (cnt = 0; cnt < 10; cnt++) {
-               msleep(100);
-               result = i1480->read(i1480, 0x80080000, 4);
-               if (result < 0) {
-                       dev_err(i1480->dev, "Can't read 0x8008000: %d\n", result);
-                       goto out;
-               }
-               if (*val == 0x55555555UL)       /* fw running? cool */
-                       goto out;
-       }
-       dev_err(i1480->dev, "Timed out waiting for fw to start\n");
-       result = -ETIMEDOUT;
-out:
-       return result;
-
-}
-
-
-/**
- * Upload MAC firmware, wait for it to start
- *
- * @i1480:     Device instance
- * @fw_name: Name of the file that contains the firmware
- *
- * This has to be called after the pre fw has been uploaded (if
- * there is any).
- */
-int i1480_mac_fw_upload(struct i1480 *i1480)
-{
-       int result = 0, deprecated_name = 0;
-       struct i1480_rceb *rcebe = (void *) i1480->evt_buf;
-
-       result = __mac_fw_upload(i1480, i1480->mac_fw_name, "MAC");
-       if (result == -ENOENT) {
-               result = __mac_fw_upload(i1480, i1480->mac_fw_name_deprecate,
-                                        "MAC");
-               deprecated_name = 1;
-       }
-       if (result < 0)
-               return result;
-       if (deprecated_name == 1)
-               dev_warn(i1480->dev,
-                        "WARNING: firmware file name %s is deprecated, "
-                        "please rename to %s\n",
-                        i1480->mac_fw_name_deprecate, i1480->mac_fw_name);
-       result = i1480_fw_is_running_q(i1480);
-       if (result < 0)
-               goto error_fw_not_running;
-       result = i1480->rc_setup ? i1480->rc_setup(i1480) : 0;
-       if (result < 0) {
-               dev_err(i1480->dev, "Cannot setup after MAC fw upload: %d\n",
-                       result);
-               goto error_setup;
-       }
-       result = i1480->wait_init_done(i1480);  /* wait init'on */
-       if (result < 0) {
-               dev_err(i1480->dev, "MAC fw '%s': Initialization timed out "
-                       "(%d)\n", i1480->mac_fw_name, result);
-               goto error_init_timeout;
-       }
-       /* verify we got the right initialization done event */
-       if (i1480->evt_result != sizeof(*rcebe)) {
-               dev_err(i1480->dev, "MAC fw '%s': initialization event returns "
-                       "wrong size (%zu bytes vs %zu needed)\n",
-                       i1480->mac_fw_name, i1480->evt_result, sizeof(*rcebe));
-               goto error_size;
-       }
-       result = -EIO;
-       if (i1480_rceb_check(i1480, &rcebe->rceb, NULL, 0, i1480_CET_VS1,
-                            i1480_EVT_RM_INIT_DONE) < 0) {
-               dev_err(i1480->dev, "wrong initialization event 0x%02x/%04x/%02x "
-                       "received; expected 0x%02x/%04x/00\n",
-                       rcebe->rceb.bEventType, le16_to_cpu(rcebe->rceb.wEvent),
-                       rcebe->rceb.bEventContext, i1480_CET_VS1,
-                       i1480_EVT_RM_INIT_DONE);
-               goto error_init_timeout;
-       }
-       result = i1480_cmd_reset(i1480);
-       if (result < 0)
-               dev_err(i1480->dev, "MAC fw '%s': MBOA reset failed (%d)\n",
-                       i1480->mac_fw_name, result);
-error_fw_not_running:
-error_init_timeout:
-error_size:
-error_setup:
-       return result;
-}
diff --git a/drivers/uwb/i1480/dfu/phy.c b/drivers/uwb/i1480/dfu/phy.c
deleted file mode 100644 (file)
index 50da452..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Wireless UWB Link 1480
- * PHY parameters upload
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Code for uploading the PHY parameters to the PHY through the UWB
- * Radio Control interface.
- *
- * We just send the data through the MPI interface using HWA-like
- * commands and then reset the PHY to make sure it is ok.
- */
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/firmware.h>
-#include <linux/usb/wusb.h>
-#include "i1480-dfu.h"
-
-
-/**
- * Write a value array to an address of the MPI interface
- *
- * @i1480:     Device descriptor
- * @data:      Data array to write
- * @size:      Size of the data array
- * @returns:   0 if ok, < 0 errno code on error.
- *
- * The data array is organized into pairs:
- *
- * ADDRESS VALUE
- *
- * ADDRESS is BE 16 bit unsigned, VALUE 8 bit unsigned. Size thus has
- * to be a multiple of three.
- */
-static
-int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size)
-{
-       int result;
-       struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf;
-       struct i1480_evt_confirm *reply = i1480->evt_buf;
-
-       BUG_ON(size > 480);
-       result = -ENOMEM;
-       cmd->rccb.bCommandType = i1480_CET_VS1;
-       cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE);
-       cmd->size = cpu_to_le16(size);
-       memcpy(cmd->data, data, size);
-       reply->rceb.bEventType = i1480_CET_VS1;
-       reply->rceb.wEvent = i1480_CMD_MPI_WRITE;
-       result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply));
-       if (result < 0)
-               goto out;
-       if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n",
-                       reply->bResultCode);
-               result = -EIO;
-       }
-out:
-       return result;
-}
-
-
-/**
- * Read a value array to from an address of the MPI interface
- *
- * @i1480:     Device descriptor
- * @data:      where to place the read array
- * @srcaddr:   Where to read from
- * @size:      Size of the data read array
- * @returns:   0 if ok, < 0 errno code on error.
- *
- * The command data array is organized into pairs ADDR0 ADDR1..., and
- * the returned data in ADDR0 VALUE0 ADDR1 VALUE1...
- *
- * We generate the command array to be a sequential read and then
- * rearrange the result.
- *
- * We use the i1480->cmd_buf for the command, i1480->evt_buf for the reply.
- *
- * As the reply has to fit in 512 bytes (i1480->evt_buffer), the max amount
- * of values we can read is (512 - sizeof(*reply)) / 3
- */
-static
-int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size)
-{
-       int result;
-       struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf;
-       struct i1480_evt_mpi_read *reply = i1480->evt_buf;
-       unsigned cnt;
-
-       memset(i1480->cmd_buf, 0x69, 512);
-       memset(i1480->evt_buf, 0x69, 512);
-
-       BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3);
-       result = -ENOMEM;
-       cmd->rccb.bCommandType = i1480_CET_VS1;
-       cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ);
-       cmd->size = cpu_to_le16(3*size);
-       for (cnt = 0; cnt < size; cnt++) {
-               cmd->data[cnt].page = (srcaddr + cnt) >> 8;
-               cmd->data[cnt].offset = (srcaddr + cnt) & 0xff;
-       }
-       reply->rceb.bEventType = i1480_CET_VS1;
-       reply->rceb.wEvent = i1480_CMD_MPI_READ;
-       result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size,
-                       sizeof(*reply) + 3*size);
-       if (result < 0)
-               goto out;
-       if (reply->bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n",
-                       reply->bResultCode);
-               result = -EIO;
-               goto out;
-       }
-       for (cnt = 0; cnt < size; cnt++) {
-               if (reply->data[cnt].page != (srcaddr + cnt) >> 8)
-                       dev_err(i1480->dev, "MPI-READ: page inconsistency at "
-                               "index %u: expected 0x%02x, got 0x%02x\n", cnt,
-                               (srcaddr + cnt) >> 8, reply->data[cnt].page);
-               if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff))
-                       dev_err(i1480->dev, "MPI-READ: offset inconsistency at "
-                               "index %u: expected 0x%02x, got 0x%02x\n", cnt,
-                               (srcaddr + cnt) & 0x00ff,
-                               reply->data[cnt].offset);
-               data[cnt] = reply->data[cnt].value;
-       }
-       result = 0;
-out:
-       return result;
-}
-
-
-/**
- * Upload a PHY firmware, wait for it to start
- *
- * @i1480:     Device instance
- * @fw_name: Name of the file that contains the firmware
- *
- * We assume the MAC fw is up and running. This means we can use the
- * MPI interface to write the PHY firmware. Once done, we issue an
- * MBOA Reset, which will force the MAC to reset and reinitialize the
- * PHY. If that works, we are ready to go.
- *
- * Max packet size for the MPI write is 512, so the max buffer is 480
- * (which gives us 160 byte triads of MSB, LSB and VAL for the data).
- */
-int i1480_phy_fw_upload(struct i1480 *i1480)
-{
-       int result;
-       const struct firmware *fw;
-       const char *data_itr, *data_top;
-       const size_t MAX_BLK_SIZE = 480;        /* 160 triads */
-       size_t data_size;
-       u8 phy_stat;
-
-       result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev);
-       if (result < 0)
-               goto out;
-       /* Loop writing data in chunks as big as possible until done. */
-       for (data_itr = fw->data, data_top = data_itr + fw->size;
-            data_itr < data_top; data_itr += MAX_BLK_SIZE) {
-               data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr));
-               result = i1480_mpi_write(i1480, data_itr, data_size);
-               if (result < 0)
-                       goto error_mpi_write;
-       }
-       /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */
-       result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1);
-       if (result < 0) {
-               dev_err(i1480->dev, "PHY: can't get status: %d\n", result);
-               goto error_mpi_status;
-       }
-       if (phy_stat != 0) {
-               result = -ENODEV;
-               dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat);
-               goto error_phy_status;
-       }
-       dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name);
-error_phy_status:
-error_mpi_status:
-error_mpi_write:
-       release_firmware(fw);
-       if (result < 0)
-               dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), "
-                       "power cycle device\n", i1480->phy_fw_name, result);
-out:
-       return result;
-}
diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c
deleted file mode 100644 (file)
index 6129a8f..0000000
+++ /dev/null
@@ -1,448 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Intel Wireless UWB Link 1480
- * USB SKU firmware upload implementation
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This driver will prepare the i1480 device to behave as a real
- * Wireless USB HWA adaptor by uploading the firmware.
- *
- * When the device is connected or driver is loaded, i1480_usb_probe()
- * is called--this will allocate and initialize the device structure,
- * fill in the pointers to the common functions (read, write,
- * wait_init_done and cmd for HWA command execution) and once that is
- * done, call the common firmware uploading routine. Then clean up and
- * return -ENODEV, as we don't attach to the device.
- *
- * The rest are the basic ops we implement that the fw upload code
- * uses to do its job. All the ops in the common code are i1480->NAME,
- * the functions are i1480_usb_NAME().
- */
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/uwb.h>
-#include <linux/usb/wusb.h>
-#include <linux/usb/wusb-wa.h>
-#include "i1480-dfu.h"
-
-struct i1480_usb {
-       struct i1480 i1480;
-       struct usb_device *usb_dev;
-       struct usb_interface *usb_iface;
-       struct urb *neep_urb;   /* URB for reading from EP1 */
-};
-
-
-static
-void i1480_usb_init(struct i1480_usb *i1480_usb)
-{
-       i1480_init(&i1480_usb->i1480);
-}
-
-
-static
-int i1480_usb_create(struct i1480_usb *i1480_usb, struct usb_interface *iface)
-{
-       struct usb_device *usb_dev = interface_to_usbdev(iface);
-       int result = -ENOMEM;
-
-       i1480_usb->usb_dev = usb_get_dev(usb_dev);      /* bind the USB device */
-       i1480_usb->usb_iface = usb_get_intf(iface);
-       usb_set_intfdata(iface, i1480_usb);             /* Bind the driver to iface0 */
-       i1480_usb->neep_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (i1480_usb->neep_urb == NULL)
-               goto error;
-       return 0;
-
-error:
-       usb_set_intfdata(iface, NULL);
-       usb_put_intf(iface);
-       usb_put_dev(usb_dev);
-       return result;
-}
-
-
-static
-void i1480_usb_destroy(struct i1480_usb *i1480_usb)
-{
-       usb_kill_urb(i1480_usb->neep_urb);
-       usb_free_urb(i1480_usb->neep_urb);
-       usb_set_intfdata(i1480_usb->usb_iface, NULL);
-       usb_put_intf(i1480_usb->usb_iface);
-       usb_put_dev(i1480_usb->usb_dev);
-}
-
-
-/**
- * Write a buffer to a memory address in the i1480 device
- *
- * @i1480:  i1480 instance
- * @memory_address:
- *          Address where to write the data buffer to.
- * @buffer: Buffer to the data
- * @size:   Size of the buffer [has to be < 512].
- * @returns: 0 if ok, < 0 errno code on error.
- *
- * Data buffers to USB cannot be on the stack or in vmalloc'ed areas,
- * so we copy it to the local i1480 buffer before proceeding. In any
- * case, we have a max size we can send.
- */
-static
-int i1480_usb_write(struct i1480 *i1480, u32 memory_address,
-                   const void *buffer, size_t size)
-{
-       int result = 0;
-       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
-       size_t buffer_size, itr = 0;
-
-       BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */
-       while (size > 0) {
-               buffer_size = size < i1480->buf_size ? size : i1480->buf_size;
-               memcpy(i1480->cmd_buf, buffer + itr, buffer_size);
-               result = usb_control_msg(
-                       i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0),
-                       0xf0, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       memory_address, (memory_address >> 16),
-                       i1480->cmd_buf, buffer_size, 100 /* FIXME: arbitrary */);
-               if (result < 0)
-                       break;
-               itr += result;
-               memory_address += result;
-               size -= result;
-       }
-       return result;
-}
-
-
-/**
- * Read a block [max size 512] of the device's memory to @i1480's buffer.
- *
- * @i1480: i1480 instance
- * @memory_address:
- *         Address where to read from.
- * @size:  Size to read. Smaller than or equal to 512.
- * @returns: >= 0 number of bytes written if ok, < 0 errno code on error.
- *
- * NOTE: if the memory address or block is incorrect, you might get a
- *       stall or a different memory read. Caller has to verify the
- *       memory address and size passed back in the @neh structure.
- */
-static
-int i1480_usb_read(struct i1480 *i1480, u32 addr, size_t size)
-{
-       ssize_t result = 0, bytes = 0;
-       size_t itr, read_size = i1480->buf_size;
-       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
-
-       BUG_ON(size > i1480->buf_size);
-       BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */
-       BUG_ON(read_size > 512);
-
-       if (addr >= 0x8000d200 && addr < 0x8000d400)    /* Yeah, HW quirk */
-               read_size = 4;
-
-       for (itr = 0; itr < size; itr += read_size) {
-               size_t itr_addr = addr + itr;
-               size_t itr_size = min(read_size, size - itr);
-               result = usb_control_msg(
-                       i1480_usb->usb_dev, usb_rcvctrlpipe(i1480_usb->usb_dev, 0),
-                       0xf0, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       itr_addr, (itr_addr >> 16),
-                       i1480->cmd_buf + itr, itr_size,
-                       100 /* FIXME: arbitrary */);
-               if (result < 0) {
-                       dev_err(i1480->dev, "%s: USB read error: %zd\n",
-                               __func__, result);
-                       goto out;
-               }
-               if (result != itr_size) {
-                       result = -EIO;
-                       dev_err(i1480->dev,
-                               "%s: partial read got only %zu bytes vs %zu expected\n",
-                               __func__, result, itr_size);
-                       goto out;
-               }
-               bytes += result;
-       }
-       result = bytes;
-out:
-       return result;
-}
-
-
-/**
- * Callback for reads on the notification/event endpoint
- *
- * Just enables the completion read handler.
- */
-static
-void i1480_usb_neep_cb(struct urb *urb)
-{
-       struct i1480 *i1480 = urb->context;
-       struct device *dev = i1480->dev;
-
-       switch (urb->status) {
-       case 0:
-               break;
-       case -ECONNRESET:       /* Not an error, but a controlled situation; */
-       case -ENOENT:           /* (we killed the URB)...so, no broadcast */
-               dev_dbg(dev, "NEEP: reset/noent %d\n", urb->status);
-               break;
-       case -ESHUTDOWN:        /* going away! */
-               dev_dbg(dev, "NEEP: down %d\n", urb->status);
-               break;
-       default:
-               dev_err(dev, "NEEP: unknown status %d\n", urb->status);
-               break;
-       }
-       i1480->evt_result = urb->actual_length;
-       complete(&i1480->evt_complete);
-       return;
-}
-
-
-/**
- * Wait for the MAC FW to initialize
- *
- * MAC FW sends a 0xfd/0101/00 notification to EP1 when done
- * initializing. Get that notification into i1480->evt_buf; upper layer
- * will verify it.
- *
- * Set i1480->evt_result with the result of getting the event or its
- * size (if successful).
- *
- * Delivers the data directly to i1480->evt_buf
- */
-static
-int i1480_usb_wait_init_done(struct i1480 *i1480)
-{
-       int result;
-       struct device *dev = i1480->dev;
-       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
-       struct usb_endpoint_descriptor *epd;
-
-       init_completion(&i1480->evt_complete);
-       i1480->evt_result = -EINPROGRESS;
-       epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc;
-       usb_fill_int_urb(i1480_usb->neep_urb, i1480_usb->usb_dev,
-                        usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress),
-                        i1480->evt_buf, i1480->buf_size,
-                        i1480_usb_neep_cb, i1480, epd->bInterval);
-       result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "init done: cannot submit NEEP read: %d\n",
-                       result);
-               goto error_submit;
-       }
-       /* Wait for the USB callback to get the data */
-       result = wait_for_completion_interruptible_timeout(
-               &i1480->evt_complete, HZ);
-       if (result <= 0) {
-               result = result == 0 ? -ETIMEDOUT : result;
-               goto error_wait;
-       }
-       usb_kill_urb(i1480_usb->neep_urb);
-       return 0;
-
-error_wait:
-       usb_kill_urb(i1480_usb->neep_urb);
-error_submit:
-       i1480->evt_result = result;
-       return result;
-}
-
-
-/**
- * Generic function for issuing commands to the i1480
- *
- * @i1480:      i1480 instance
- * @cmd_name:   Name of the command (for error messages)
- * @cmd:        Pointer to command buffer
- * @cmd_size:   Size of the command buffer
- * @reply:      Buffer for the reply event
- * @reply_size: Expected size back (including RCEB); the reply buffer
- *              is assumed to be as big as this.
- * @returns:    >= 0 size of the returned event data if ok,
- *              < 0 errno code on error.
- *
- * Arms the NE handle, issues the command to the device and checks the
- * basics of the reply event.
- */
-static
-int i1480_usb_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size)
-{
-       int result;
-       struct device *dev = i1480->dev;
-       struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480);
-       struct usb_endpoint_descriptor *epd;
-       struct uwb_rccb *cmd = i1480->cmd_buf;
-       u8 iface_no;
-
-       /* Post a read on the notification & event endpoint */
-       iface_no = i1480_usb->usb_iface->cur_altsetting->desc.bInterfaceNumber;
-       epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc;
-       usb_fill_int_urb(
-               i1480_usb->neep_urb, i1480_usb->usb_dev,
-               usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress),
-               i1480->evt_buf, i1480->buf_size,
-               i1480_usb_neep_cb, i1480, epd->bInterval);
-       result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL);
-       if (result < 0) {
-               dev_err(dev, "%s: cannot submit NEEP read: %d\n",
-                       cmd_name, result);
-               goto error_submit_ep1;
-       }
-       /* Now post the command on EP0 */
-       result = usb_control_msg(
-               i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0),
-               WA_EXEC_RC_CMD,
-               USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
-               0, iface_no,
-               cmd, cmd_size,
-               100 /* FIXME: this is totally arbitrary */);
-       if (result < 0) {
-               dev_err(dev, "%s: control request failed: %d\n",
-                       cmd_name, result);
-               goto error_submit_ep0;
-       }
-       return result;
-
-error_submit_ep0:
-       usb_kill_urb(i1480_usb->neep_urb);
-error_submit_ep1:
-       return result;
-}
-
-
-/*
- * Probe a i1480 device for uploading firmware.
- *
- * We attach only to interface #0, which is the radio control interface.
- */
-static
-int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(iface);
-       struct i1480_usb *i1480_usb;
-       struct i1480 *i1480;
-       struct device *dev = &iface->dev;
-       int result;
-
-       result = -ENODEV;
-       if (iface->cur_altsetting->desc.bInterfaceNumber != 0) {
-               dev_dbg(dev, "not attaching to iface %d\n",
-                       iface->cur_altsetting->desc.bInterfaceNumber);
-               goto error;
-       }
-       if (iface->num_altsetting > 1 &&
-                       le16_to_cpu(udev->descriptor.idProduct) == 0xbabe) {
-               /* Need altsetting #1 [HW QUIRK] or EP1 won't work */
-               result = usb_set_interface(interface_to_usbdev(iface), 0, 1);
-               if (result < 0)
-                       dev_warn(dev,
-                                "can't set altsetting 1 on iface 0: %d\n",
-                                result);
-       }
-
-       if (iface->cur_altsetting->desc.bNumEndpoints < 1)
-               return -ENODEV;
-
-       result = -ENOMEM;
-       i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL);
-       if (i1480_usb == NULL) {
-               dev_err(dev, "Unable to allocate instance\n");
-               goto error;
-       }
-       i1480_usb_init(i1480_usb);
-
-       i1480 = &i1480_usb->i1480;
-       i1480->buf_size = 512;
-       i1480->cmd_buf = kmalloc_array(2, i1480->buf_size, GFP_KERNEL);
-       if (i1480->cmd_buf == NULL) {
-               dev_err(dev, "Cannot allocate transfer buffers\n");
-               result = -ENOMEM;
-               goto error_buf_alloc;
-       }
-       i1480->evt_buf = i1480->cmd_buf + i1480->buf_size;
-
-       result = i1480_usb_create(i1480_usb, iface);
-       if (result < 0) {
-               dev_err(dev, "Cannot create instance: %d\n", result);
-               goto error_create;
-       }
-
-       /* setup the fops and upload the firmware */
-       i1480->pre_fw_name = "i1480-pre-phy-0.0.bin";
-       i1480->mac_fw_name = "i1480-usb-0.0.bin";
-       i1480->mac_fw_name_deprecate = "ptc-0.0.bin";
-       i1480->phy_fw_name = "i1480-phy-0.0.bin";
-       i1480->dev = &iface->dev;
-       i1480->write = i1480_usb_write;
-       i1480->read = i1480_usb_read;
-       i1480->rc_setup = NULL;
-       i1480->wait_init_done = i1480_usb_wait_init_done;
-       i1480->cmd = i1480_usb_cmd;
-
-       result = i1480_fw_upload(&i1480_usb->i1480);    /* the real thing */
-       if (result >= 0) {
-               usb_reset_device(i1480_usb->usb_dev);
-               result = -ENODEV;       /* we don't want to bind to the iface */
-       }
-       i1480_usb_destroy(i1480_usb);
-error_create:
-       kfree(i1480->cmd_buf);
-error_buf_alloc:
-       kfree(i1480_usb);
-error:
-       return result;
-}
-
-MODULE_FIRMWARE("i1480-pre-phy-0.0.bin");
-MODULE_FIRMWARE("i1480-usb-0.0.bin");
-MODULE_FIRMWARE("i1480-phy-0.0.bin");
-
-#define i1480_USB_DEV(v, p)                            \
-{                                                      \
-       .match_flags = USB_DEVICE_ID_MATCH_DEVICE       \
-                | USB_DEVICE_ID_MATCH_DEV_INFO         \
-                | USB_DEVICE_ID_MATCH_INT_INFO,        \
-       .idVendor = (v),                                \
-       .idProduct = (p),                               \
-       .bDeviceClass = 0xff,                           \
-       .bDeviceSubClass = 0xff,                        \
-       .bDeviceProtocol = 0xff,                        \
-       .bInterfaceClass = 0xff,                        \
-       .bInterfaceSubClass = 0xff,                     \
-       .bInterfaceProtocol = 0xff,                     \
-}
-
-
-/** USB device ID's that we handle */
-static const struct usb_device_id i1480_usb_id_table[] = {
-       i1480_USB_DEV(0x8086, 0xdf3b),
-       i1480_USB_DEV(0x15a9, 0x0005),
-       i1480_USB_DEV(0x07d1, 0x3802),
-       i1480_USB_DEV(0x050d, 0x305a),
-       i1480_USB_DEV(0x3495, 0x3007),
-       {},
-};
-MODULE_DEVICE_TABLE(usb, i1480_usb_id_table);
-
-
-static struct usb_driver i1480_dfu_driver = {
-       .name =         "i1480-dfu-usb",
-       .id_table =     i1480_usb_id_table,
-       .probe =        i1480_usb_probe,
-       .disconnect =   NULL,
-};
-
-module_usb_driver(i1480_dfu_driver);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Intel Wireless UWB Link 1480 firmware uploader for USB");
-MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/i1480/i1480-est.c b/drivers/uwb/i1480/i1480-est.c
deleted file mode 100644 (file)
index 1346c40..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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 <linux/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);
diff --git a/drivers/uwb/ie-rcv.c b/drivers/uwb/ie-rcv.c
deleted file mode 100644 (file)
index 51a4706..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * IE Received notification handling.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/bitmap.h>
-#include "uwb-internal.h"
-
-/*
- * Process an incoming IE Received notification.
- */
-int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *evt)
-{
-       int result = -EINVAL;
-       struct device *dev = &evt->rc->uwb_dev.dev;
-       struct uwb_rc_evt_ie_rcv *iercv;
-
-       /* Is there enough data to decode it? */
-       if (evt->notif.size < sizeof(*iercv)) {
-               dev_err(dev, "IE Received notification: Not enough data to "
-                       "decode (%zu vs %zu bytes needed)\n",
-                       evt->notif.size, sizeof(*iercv));
-               goto error;
-       }
-       iercv = container_of(evt->notif.rceb, struct uwb_rc_evt_ie_rcv, rceb);
-
-       dev_dbg(dev, "IE received, element ID=%d\n", iercv->IEData[0]);
-
-       if (iercv->IEData[0] == UWB_RELINQUISH_REQUEST_IE) {
-               dev_warn(dev, "unhandled Relinquish Request IE\n");
-       }
-
-       return 0;
-error:
-       return result;
-}
diff --git a/drivers/uwb/ie.c b/drivers/uwb/ie.c
deleted file mode 100644 (file)
index b11678d..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Information Element Handling
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- * Reinette Chatre <reinette.chatre@intel.com>
- *
- * FIXME: docs
- */
-
-#include <linux/slab.h>
-#include <linux/export.h>
-#include "uwb-internal.h"
-
-/**
- * uwb_ie_next - get the next IE in a buffer
- * @ptr: start of the buffer containing the IE data
- * @len: length of the buffer
- *
- * Both @ptr and @len are updated so subsequent calls to uwb_ie_next()
- * will get the next IE.
- *
- * NULL is returned (and @ptr and @len will not be updated) if there
- * are no more IEs in the buffer or the buffer is too short.
- */
-struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len)
-{
-       struct uwb_ie_hdr *hdr;
-       size_t ie_len;
-
-       if (*len < sizeof(struct uwb_ie_hdr))
-               return NULL;
-
-       hdr = *ptr;
-       ie_len = sizeof(struct uwb_ie_hdr) + hdr->length;
-
-       if (*len < ie_len)
-               return NULL;
-
-       *ptr += ie_len;
-       *len -= ie_len;
-
-       return hdr;
-}
-EXPORT_SYMBOL_GPL(uwb_ie_next);
-
-/**
- * uwb_ie_dump_hex - print IEs to a character buffer
- * @ies: the IEs to print.
- * @len: length of all the IEs.
- * @buf: the destination buffer.
- * @size: size of @buf.
- *
- * Returns the number of characters written.
- */
-int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len,
-                   char *buf, size_t size)
-{
-       void *ptr;
-       const struct uwb_ie_hdr *ie;
-       int r = 0;
-       u8 *d;
-
-       ptr = (void *)ies;
-       for (;;) {
-               ie = uwb_ie_next(&ptr, &len);
-               if (!ie)
-                       break;
-
-               r += scnprintf(buf + r, size - r, "%02x %02x",
-                              (unsigned)ie->element_id,
-                              (unsigned)ie->length);
-               d = (uint8_t *)ie + sizeof(struct uwb_ie_hdr);
-               while (d != ptr && r < size)
-                       r += scnprintf(buf + r, size - r, " %02x", (unsigned)*d++);
-               if (r < size)
-                       buf[r++] = '\n';
-       };
-
-       return r;
-}
-
-/**
- * Get the IEs that a radio controller is sending in its beacon
- *
- * @uwb_rc:  UWB Radio Controller
- * @returns: Size read from the system
- *
- * We don't need to lock the uwb_rc's mutex because we don't modify
- * anything. Once done with the iedata buffer, call
- * uwb_rc_ie_release(iedata). Don't call kfree on it.
- */
-static
-ssize_t uwb_rc_get_ie(struct uwb_rc *uwb_rc, struct uwb_rc_evt_get_ie **pget_ie)
-{
-       ssize_t result;
-       struct device *dev = &uwb_rc->uwb_dev.dev;
-       struct uwb_rccb *cmd = NULL;
-       struct uwb_rceb *reply = NULL;
-       struct uwb_rc_evt_get_ie *get_ie;
-
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               return -ENOMEM;
-
-       cmd->bCommandType = UWB_RC_CET_GENERAL;
-       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_GET_IE);
-       result = uwb_rc_vcmd(uwb_rc, "GET_IE", cmd, sizeof(*cmd),
-                            UWB_RC_CET_GENERAL, UWB_RC_CMD_GET_IE,
-                            &reply);
-       kfree(cmd);
-       if (result < 0)
-               return result;
-
-       get_ie = container_of(reply, struct uwb_rc_evt_get_ie, rceb);
-       if (result < sizeof(*get_ie)) {
-               dev_err(dev, "not enough data returned for decoding GET IE "
-                       "(%zu bytes received vs %zu needed)\n",
-                       result, sizeof(*get_ie));
-               return -EINVAL;
-       } else if (result < sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)) {
-               dev_err(dev, "not enough data returned for decoding GET IE "
-                       "payload (%zu bytes received vs %zu needed)\n", result,
-                       sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength));
-               return -EINVAL;
-       }
-
-       *pget_ie = get_ie;
-       return result;
-}
-
-
-/**
- * Replace all IEs currently being transmitted by a device
- *
- * @cmd:    pointer to the SET-IE command with the IEs to set
- * @size:   size of @buf
- */
-int uwb_rc_set_ie(struct uwb_rc *rc, struct uwb_rc_cmd_set_ie *cmd)
-{
-       int result;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_evt_set_ie reply;
-
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_SET_IE;
-       result = uwb_rc_cmd(rc, "SET-IE", &cmd->rccb,
-                           sizeof(*cmd) + le16_to_cpu(cmd->wIELength),
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       else if (result != sizeof(reply)) {
-               dev_err(dev, "SET-IE: not enough data to decode reply "
-                       "(%d bytes received vs %zu needed)\n",
-                       result, sizeof(reply));
-               result = -EIO;
-       } else if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(dev, "SET-IE: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
-               result = -EIO;
-       } else
-               result = 0;
-error_cmd:
-       return result;
-}
-
-/* Cleanup the whole IE management subsystem */
-void uwb_rc_ie_init(struct uwb_rc *uwb_rc)
-{
-       mutex_init(&uwb_rc->ies_mutex);
-}
-
-
-/**
- * uwb_rc_ie_setup - setup a radio controller's IE manager
- * @uwb_rc: the radio controller.
- *
- * The current set of IEs are obtained from the hardware with a GET-IE
- * command (since the radio controller is not yet beaconing this will
- * be just the hardware's MAC and PHY Capability IEs).
- *
- * Returns 0 on success; -ve on an error.
- */
-int uwb_rc_ie_setup(struct uwb_rc *uwb_rc)
-{
-       struct uwb_rc_evt_get_ie *ie_info = NULL;
-       int capacity;
-
-       capacity = uwb_rc_get_ie(uwb_rc, &ie_info);
-       if (capacity < 0)
-               return capacity;
-
-       mutex_lock(&uwb_rc->ies_mutex);
-
-       uwb_rc->ies = (struct uwb_rc_cmd_set_ie *)ie_info;
-       uwb_rc->ies->rccb.bCommandType = UWB_RC_CET_GENERAL;
-       uwb_rc->ies->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_IE);
-       uwb_rc->ies_capacity = capacity;
-
-       mutex_unlock(&uwb_rc->ies_mutex);
-
-       return 0;
-}
-
-
-/* Cleanup the whole IE management subsystem */
-void uwb_rc_ie_release(struct uwb_rc *uwb_rc)
-{
-       kfree(uwb_rc->ies);
-       uwb_rc->ies = NULL;
-       uwb_rc->ies_capacity = 0;
-}
-
-
-static int uwb_rc_ie_add_one(struct uwb_rc *rc, const struct uwb_ie_hdr *new_ie)
-{
-       struct uwb_rc_cmd_set_ie *new_ies;
-       void *ptr, *prev_ie;
-       struct uwb_ie_hdr *ie;
-       size_t length, new_ie_len, new_capacity, size, prev_size;
-
-       length = le16_to_cpu(rc->ies->wIELength);
-       new_ie_len = sizeof(struct uwb_ie_hdr) + new_ie->length;
-       new_capacity = sizeof(struct uwb_rc_cmd_set_ie) + length + new_ie_len;
-
-       if (new_capacity > rc->ies_capacity) {
-               new_ies = krealloc(rc->ies, new_capacity, GFP_KERNEL);
-               if (!new_ies)
-                       return -ENOMEM;
-               rc->ies = new_ies;
-       }
-
-       ptr = rc->ies->IEData;
-       size = length;
-       for (;;) {
-               prev_ie = ptr;
-               prev_size = size;
-               ie = uwb_ie_next(&ptr, &size);
-               if (!ie || ie->element_id > new_ie->element_id)
-                       break;
-       }
-
-       memmove(prev_ie + new_ie_len, prev_ie, prev_size);
-       memcpy(prev_ie, new_ie, new_ie_len);
-       rc->ies->wIELength = cpu_to_le16(length + new_ie_len);
-
-       return 0;
-}
-
-/**
- * uwb_rc_ie_add - add new IEs to the radio controller's beacon
- * @uwb_rc: the radio controller.
- * @ies: the buffer containing the new IE or IEs to be added to
- *       the device's beacon.
- * @size: length of all the IEs.
- *
- * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB
- * after the device sent the first beacon that includes the IEs specified
- * in the SET IE command. We thus cannot send this command if the device is
- * not beaconing. Instead, a SET IE command will be sent later right after
- * we start beaconing.
- *
- * Setting an IE on the device will overwrite all current IEs in device. So
- * we take the current IEs being transmitted by the device, insert the
- * new one, and call SET IE with all the IEs needed.
- *
- * Returns 0 on success; or -ENOMEM.
- */
-int uwb_rc_ie_add(struct uwb_rc *uwb_rc,
-                 const struct uwb_ie_hdr *ies, size_t size)
-{
-       int result = 0;
-       void *ptr;
-       const struct uwb_ie_hdr *ie;
-
-       mutex_lock(&uwb_rc->ies_mutex);
-
-       ptr = (void *)ies;
-       for (;;) {
-               ie = uwb_ie_next(&ptr, &size);
-               if (!ie)
-                       break;
-
-               result = uwb_rc_ie_add_one(uwb_rc, ie);
-               if (result < 0)
-                       break;
-       }
-       if (result >= 0) {
-               if (size == 0) {
-                       if (uwb_rc->beaconing != -1)
-                               result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies);
-               } else
-                       result = -EINVAL;
-       }
-
-       mutex_unlock(&uwb_rc->ies_mutex);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_ie_add);
-
-
-/*
- * Remove an IE from internal cache
- *
- * We are dealing with our internal IE cache so no need to verify that the
- * IEs are valid (it has been done already).
- *
- * Should be called with ies_mutex held
- *
- * We do not break out once an IE is found in the cache. It is currently
- * possible to have more than one IE with the same ID included in the
- * beacon. We don't reallocate, we just mark the size smaller.
- */
-static
-void uwb_rc_ie_cache_rm(struct uwb_rc *uwb_rc, enum uwb_ie to_remove)
-{
-       struct uwb_ie_hdr *ie;
-       size_t len = le16_to_cpu(uwb_rc->ies->wIELength);
-       void *ptr;
-       size_t size;
-
-       ptr = uwb_rc->ies->IEData;
-       size = len;
-       for (;;) {
-               ie = uwb_ie_next(&ptr, &size);
-               if (!ie)
-                       break;
-               if (ie->element_id == to_remove) {
-                       len -= sizeof(struct uwb_ie_hdr) + ie->length;
-                       memmove(ie, ptr, size);
-                       ptr = ie;
-               }
-       }
-       uwb_rc->ies->wIELength = cpu_to_le16(len);
-}
-
-
-/**
- * uwb_rc_ie_rm - remove an IE from the radio controller's beacon
- * @uwb_rc: the radio controller.
- * @element_id: the element ID of the IE to remove.
- *
- * Only IEs previously added with uwb_rc_ie_add() may be removed.
- *
- * Returns 0 on success; or -ve the SET-IE command to the radio
- * controller failed.
- */
-int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id)
-{
-       int result = 0;
-
-       mutex_lock(&uwb_rc->ies_mutex);
-
-       uwb_rc_ie_cache_rm(uwb_rc, element_id);
-
-       if (uwb_rc->beaconing != -1)
-               result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies);
-
-       mutex_unlock(&uwb_rc->ies_mutex);
-
-       return result;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_ie_rm);
diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c
deleted file mode 100644 (file)
index 3e5c07f..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Life cycle of devices
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/export.h>
-#include <linux/err.h>
-#include <linux/kdev_t.h>
-#include <linux/random.h>
-#include <linux/stat.h>
-#include "uwb-internal.h"
-
-/* We initialize addresses to 0xff (invalid, as it is bcast) */
-static inline void uwb_dev_addr_init(struct uwb_dev_addr *addr)
-{
-       memset(&addr->data, 0xff, sizeof(addr->data));
-}
-
-static inline void uwb_mac_addr_init(struct uwb_mac_addr *addr)
-{
-       memset(&addr->data, 0xff, sizeof(addr->data));
-}
-
-/*
- * Add callback @new to be called when an event occurs in @rc.
- */
-int uwb_notifs_register(struct uwb_rc *rc, struct uwb_notifs_handler *new)
-{
-       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
-               return -ERESTARTSYS;
-       list_add(&new->list_node, &rc->notifs_chain.list);
-       mutex_unlock(&rc->notifs_chain.mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(uwb_notifs_register);
-
-/*
- * Remove event handler (callback)
- */
-int uwb_notifs_deregister(struct uwb_rc *rc, struct uwb_notifs_handler *entry)
-{
-       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
-               return -ERESTARTSYS;
-       list_del(&entry->list_node);
-       mutex_unlock(&rc->notifs_chain.mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(uwb_notifs_deregister);
-
-/*
- * Notify all event handlers of a given event on @rc
- *
- * We are called with a valid reference to the device, or NULL if the
- * event is not for a particular event (e.g., a BG join event).
- */
-void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event)
-{
-       struct uwb_notifs_handler *handler;
-       if (mutex_lock_interruptible(&rc->notifs_chain.mutex))
-               return;
-       if (!list_empty(&rc->notifs_chain.list)) {
-               list_for_each_entry(handler, &rc->notifs_chain.list, list_node) {
-                       handler->cb(handler->data, uwb_dev, event);
-               }
-       }
-       mutex_unlock(&rc->notifs_chain.mutex);
-}
-
-/*
- * Release the backing device of a uwb_dev that has been dynamically allocated.
- */
-static void uwb_dev_sys_release(struct device *dev)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-
-       uwb_bce_put(uwb_dev->bce);
-       memset(uwb_dev, 0x69, sizeof(*uwb_dev));
-       kfree(uwb_dev);
-}
-
-/*
- * Initialize a UWB device instance
- *
- * Alloc, zero and call this function.
- */
-void uwb_dev_init(struct uwb_dev *uwb_dev)
-{
-       mutex_init(&uwb_dev->mutex);
-       device_initialize(&uwb_dev->dev);
-       uwb_dev->dev.release = uwb_dev_sys_release;
-       uwb_dev_addr_init(&uwb_dev->dev_addr);
-       uwb_mac_addr_init(&uwb_dev->mac_addr);
-       bitmap_fill(uwb_dev->streams, UWB_NUM_GLOBAL_STREAMS);
-}
-
-static ssize_t uwb_dev_EUI_48_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       char addr[UWB_ADDR_STRSIZE];
-
-       uwb_mac_addr_print(addr, sizeof(addr), &uwb_dev->mac_addr);
-       return sprintf(buf, "%s\n", addr);
-}
-static DEVICE_ATTR(EUI_48, S_IRUGO, uwb_dev_EUI_48_show, NULL);
-
-static ssize_t uwb_dev_DevAddr_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       char addr[UWB_ADDR_STRSIZE];
-
-       uwb_dev_addr_print(addr, sizeof(addr), &uwb_dev->dev_addr);
-       return sprintf(buf, "%s\n", addr);
-}
-static DEVICE_ATTR(DevAddr, S_IRUGO, uwb_dev_DevAddr_show, NULL);
-
-/*
- * Show the BPST of this device.
- *
- * Calculated from the receive time of the device's beacon and it's
- * slot number.
- */
-static ssize_t uwb_dev_BPST_show(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_beca_e *bce;
-       struct uwb_beacon_frame *bf;
-       u16 bpst;
-
-       bce = uwb_dev->bce;
-       mutex_lock(&bce->mutex);
-       bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo;
-       bpst = bce->be->wBPSTOffset
-               - (u16)(bf->Beacon_Slot_Number * UWB_BEACON_SLOT_LENGTH_US);
-       mutex_unlock(&bce->mutex);
-
-       return sprintf(buf, "%d\n", bpst);
-}
-static DEVICE_ATTR(BPST, S_IRUGO, uwb_dev_BPST_show, NULL);
-
-/*
- * Show the IEs a device is beaconing
- *
- * We need to access the beacon cache, so we just lock it really
- * quick, print the IEs and unlock.
- *
- * We have a reference on the cache entry, so that should be
- * quite safe.
- */
-static ssize_t uwb_dev_IEs_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-
-       return uwb_bce_print_IEs(uwb_dev, uwb_dev->bce, buf, PAGE_SIZE);
-}
-static DEVICE_ATTR(IEs, S_IRUGO | S_IWUSR, uwb_dev_IEs_show, NULL);
-
-static ssize_t uwb_dev_LQE_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_beca_e *bce = uwb_dev->bce;
-       size_t result;
-
-       mutex_lock(&bce->mutex);
-       result = stats_show(&uwb_dev->bce->lqe_stats, buf);
-       mutex_unlock(&bce->mutex);
-       return result;
-}
-
-static ssize_t uwb_dev_LQE_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_beca_e *bce = uwb_dev->bce;
-       ssize_t result;
-
-       mutex_lock(&bce->mutex);
-       result = stats_store(&uwb_dev->bce->lqe_stats, buf, size);
-       mutex_unlock(&bce->mutex);
-       return result;
-}
-static DEVICE_ATTR(LQE, S_IRUGO | S_IWUSR, uwb_dev_LQE_show, uwb_dev_LQE_store);
-
-static ssize_t uwb_dev_RSSI_show(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       struct uwb_beca_e *bce = uwb_dev->bce;
-       size_t result;
-
-       mutex_lock(&bce->mutex);
-       result = stats_show(&uwb_dev->bce->rssi_stats, buf);
-       mutex_unlock(&bce->mutex);
-       return result;
-}
-
-static ssize_t uwb_dev_RSSI_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_beca_e *bce = uwb_dev->bce;
-       ssize_t result;
-
-       mutex_lock(&bce->mutex);
-       result = stats_store(&uwb_dev->bce->rssi_stats, buf, size);
-       mutex_unlock(&bce->mutex);
-       return result;
-}
-static DEVICE_ATTR(RSSI, S_IRUGO | S_IWUSR, uwb_dev_RSSI_show, uwb_dev_RSSI_store);
-
-
-static struct attribute *uwb_dev_attrs[] = {
-       &dev_attr_EUI_48.attr,
-       &dev_attr_DevAddr.attr,
-       &dev_attr_BPST.attr,
-       &dev_attr_IEs.attr,
-       &dev_attr_LQE.attr,
-       &dev_attr_RSSI.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(uwb_dev);
-
-/* UWB bus type. */
-struct bus_type uwb_bus_type = {
-       .name =         "uwb",
-       .dev_groups =   uwb_dev_groups,
-};
-
-/**
- * Device SYSFS registration
- */
-static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev)
-{
-       struct device *dev;
-
-       dev = &uwb_dev->dev;
-       dev->parent = parent_dev;
-       dev_set_drvdata(dev, uwb_dev);
-
-       return device_add(dev);
-}
-
-
-static void __uwb_dev_sys_rm(struct uwb_dev *uwb_dev)
-{
-       dev_set_drvdata(&uwb_dev->dev, NULL);
-       device_del(&uwb_dev->dev);
-}
-
-
-/**
- * Register and initialize a new UWB device
- *
- * Did you call uwb_dev_init() on it?
- *
- * @parent_rc: is the parent radio controller who has the link to the
- *             device. When registering the UWB device that is a UWB
- *             Radio Controller, we point back to it.
- *
- * If registering the device that is part of a radio, caller has set
- * rc->uwb_dev->dev. Otherwise it is to be left NULL--a new one will
- * be allocated.
- */
-int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
-               struct uwb_rc *parent_rc)
-{
-       int result;
-       struct device *dev;
-
-       BUG_ON(uwb_dev == NULL);
-       BUG_ON(parent_dev == NULL);
-       BUG_ON(parent_rc == NULL);
-
-       mutex_lock(&uwb_dev->mutex);
-       dev = &uwb_dev->dev;
-       uwb_dev->rc = parent_rc;
-       result = __uwb_dev_sys_add(uwb_dev, parent_dev);
-       if (result < 0)
-               printk(KERN_ERR "UWB: unable to register dev %s with sysfs: %d\n",
-                      dev_name(dev), result);
-       mutex_unlock(&uwb_dev->mutex);
-       return result;
-}
-
-
-void uwb_dev_rm(struct uwb_dev *uwb_dev)
-{
-       mutex_lock(&uwb_dev->mutex);
-       __uwb_dev_sys_rm(uwb_dev);
-       mutex_unlock(&uwb_dev->mutex);
-}
-
-
-static
-int __uwb_dev_try_get(struct device *dev, void *__target_uwb_dev)
-{
-       struct uwb_dev *target_uwb_dev = __target_uwb_dev;
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-       if (uwb_dev == target_uwb_dev) {
-               uwb_dev_get(uwb_dev);
-               return 1;
-       } else
-               return 0;
-}
-
-
-/**
- * Given a UWB device descriptor, validate and refcount it
- *
- * @returns NULL if the device does not exist or is quiescing; the ptr to
- *               it otherwise.
- */
-struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev)
-{
-       if (uwb_dev_for_each(rc, __uwb_dev_try_get, uwb_dev))
-               return uwb_dev;
-       else
-               return NULL;
-}
-EXPORT_SYMBOL_GPL(uwb_dev_try_get);
-
-
-/**
- * Remove a device from the system [grunt for other functions]
- */
-int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc)
-{
-       struct device *dev = &uwb_dev->dev;
-       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
-
-       uwb_mac_addr_print(macbuf, sizeof(macbuf), &uwb_dev->mac_addr);
-       uwb_dev_addr_print(devbuf, sizeof(devbuf), &uwb_dev->dev_addr);
-       dev_info(dev, "uwb device (mac %s dev %s) disconnected from %s %s\n",
-                macbuf, devbuf,
-                uwb_dev->dev.bus->name,
-                rc ? dev_name(&(rc->uwb_dev.dev)) : "");
-       uwb_dev_rm(uwb_dev);
-       list_del(&uwb_dev->bce->node);
-       uwb_bce_put(uwb_dev->bce);
-       uwb_dev_put(uwb_dev);   /* for the creation in _onair() */
-
-       return 0;
-}
-
-
-/**
- * A device went off the air, clean up after it!
- *
- * This is called by the UWB Daemon (through the beacon purge function
- * uwb_bcn_cache_purge) when it is detected that a device has been in
- * radio silence for a while.
- *
- * If this device is actually a local radio controller we don't need
- * to go through the offair process, as it is not registered as that.
- *
- * NOTE: uwb_bcn_cache.mutex is held!
- */
-void uwbd_dev_offair(struct uwb_beca_e *bce)
-{
-       struct uwb_dev *uwb_dev;
-
-       uwb_dev = bce->uwb_dev;
-       if (uwb_dev) {
-               uwb_notify(uwb_dev->rc, uwb_dev, UWB_NOTIF_OFFAIR);
-               __uwb_dev_offair(uwb_dev, uwb_dev->rc);
-       }
-}
-
-
-/**
- * A device went on the air, start it up!
- *
- * This is called by the UWB Daemon when it is detected that a device
- * has popped up in the radio range of the radio controller.
- *
- * It will just create the freaking device, register the beacon and
- * stuff and yatla, done.
- *
- *
- * NOTE: uwb_beca.mutex is held, bce->mutex is held
- */
-void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce)
-{
-       int result;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_dev *uwb_dev;
-       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
-
-       uwb_mac_addr_print(macbuf, sizeof(macbuf), bce->mac_addr);
-       uwb_dev_addr_print(devbuf, sizeof(devbuf), &bce->dev_addr);
-       uwb_dev = kzalloc(sizeof(struct uwb_dev), GFP_KERNEL);
-       if (uwb_dev == NULL) {
-               dev_err(dev, "new device %s: Cannot allocate memory\n",
-                       macbuf);
-               return;
-       }
-       uwb_dev_init(uwb_dev);          /* This sets refcnt to one, we own it */
-       uwb_dev->dev.bus = &uwb_bus_type;
-       uwb_dev->mac_addr = *bce->mac_addr;
-       uwb_dev->dev_addr = bce->dev_addr;
-       dev_set_name(&uwb_dev->dev, "%s", macbuf);
-
-       /* plug the beacon cache */
-       bce->uwb_dev = uwb_dev;
-       uwb_dev->bce = bce;
-       uwb_bce_get(bce);               /* released in uwb_dev_sys_release() */
-
-       result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc);
-       if (result < 0) {
-               dev_err(dev, "new device %s: cannot instantiate device\n",
-                       macbuf);
-               goto error_dev_add;
-       }
-
-       dev_info(dev, "uwb device (mac %s dev %s) connected to %s %s\n",
-                macbuf, devbuf, uwb_dev->dev.bus->name,
-                dev_name(&(rc->uwb_dev.dev)));
-       uwb_notify(rc, uwb_dev, UWB_NOTIF_ONAIR);
-       return;
-
-error_dev_add:
-       bce->uwb_dev = NULL;
-       uwb_bce_put(bce);
-       kfree(uwb_dev);
-       return;
-}
-
-/**
- * Iterate over the list of UWB devices, calling a @function on each
- *
- * See docs for bus_for_each()....
- *
- * @rc:       radio controller for the devices.
- * @function: function to call.
- * @priv:     data to pass to @function.
- * @returns:  0 if no invocation of function() returned a value
- *            different to zero. That value otherwise.
- */
-int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f function, void *priv)
-{
-       return device_for_each_child(&rc->uwb_dev.dev, priv, function);
-}
-EXPORT_SYMBOL_GPL(uwb_dev_for_each);
diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c
deleted file mode 100644 (file)
index ee31b22..0000000
+++ /dev/null
@@ -1,569 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Life cycle of radio controllers
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- *
- * A UWB radio controller is also a UWB device, so it embeds one...
- *
- * List of RCs comes from the 'struct class uwb_rc_class'.
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/random.h>
-#include <linux/kdev_t.h>
-#include <linux/etherdevice.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-static int uwb_rc_index_match(struct device *dev, const void *data)
-{
-       const int *index = data;
-       struct uwb_rc *rc = dev_get_drvdata(dev);
-
-       if (rc->index == *index)
-               return 1;
-       return 0;
-}
-
-static struct uwb_rc *uwb_rc_find_by_index(int index)
-{
-       struct device *dev;
-       struct uwb_rc *rc = NULL;
-
-       dev = class_find_device(&uwb_rc_class, NULL, &index, uwb_rc_index_match);
-       if (dev) {
-               rc = dev_get_drvdata(dev);
-               put_device(dev);
-       }
-
-       return rc;
-}
-
-static int uwb_rc_new_index(void)
-{
-       int index = 0;
-
-       for (;;) {
-               if (!uwb_rc_find_by_index(index))
-                       return index;
-               if (++index < 0)
-                       index = 0;
-       }
-}
-
-/**
- * Release the backing device of a uwb_rc that has been dynamically allocated.
- */
-static void uwb_rc_sys_release(struct device *dev)
-{
-       struct uwb_dev *uwb_dev = container_of(dev, struct uwb_dev, dev);
-       struct uwb_rc *rc = container_of(uwb_dev, struct uwb_rc, uwb_dev);
-
-       uwb_rc_ie_release(rc);
-       kfree(rc);
-}
-
-
-void uwb_rc_init(struct uwb_rc *rc)
-{
-       struct uwb_dev *uwb_dev = &rc->uwb_dev;
-
-       uwb_dev_init(uwb_dev);
-       rc->uwb_dev.dev.class = &uwb_rc_class;
-       rc->uwb_dev.dev.release = uwb_rc_sys_release;
-       uwb_rc_neh_create(rc);
-       rc->beaconing = -1;
-       rc->scan_type = UWB_SCAN_DISABLED;
-       INIT_LIST_HEAD(&rc->notifs_chain.list);
-       mutex_init(&rc->notifs_chain.mutex);
-       INIT_LIST_HEAD(&rc->uwb_beca.list);
-       mutex_init(&rc->uwb_beca.mutex);
-       uwb_drp_avail_init(rc);
-       uwb_rc_ie_init(rc);
-       uwb_rsv_init(rc);
-       uwb_rc_pal_init(rc);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_init);
-
-
-struct uwb_rc *uwb_rc_alloc(void)
-{
-       struct uwb_rc *rc;
-       rc = kzalloc(sizeof(*rc), GFP_KERNEL);
-       if (rc == NULL)
-               return NULL;
-       uwb_rc_init(rc);
-       return rc;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_alloc);
-
-/*
- * Show the ASIE that is broadcast in the UWB beacon by this uwb_rc device.
- */
-static ssize_t ASIE_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_ie_hdr *ie;
-       void *ptr;
-       size_t len;
-       int result = 0;
-
-       /* init empty buffer. */
-       result = scnprintf(buf, PAGE_SIZE, "\n");
-       mutex_lock(&rc->ies_mutex);
-       /* walk IEData looking for an ASIE. */
-       ptr = rc->ies->IEData;
-       len = le16_to_cpu(rc->ies->wIELength);
-       for (;;) {
-               ie = uwb_ie_next(&ptr, &len);
-               if (!ie)
-                       break;
-               if (ie->element_id == UWB_APP_SPEC_IE) {
-                       result = uwb_ie_dump_hex(ie,
-                                       ie->length + sizeof(struct uwb_ie_hdr),
-                                       buf, PAGE_SIZE);
-                       break;
-               }
-       }
-       mutex_unlock(&rc->ies_mutex);
-
-       return result;
-}
-
-/*
- * Update the ASIE that is broadcast in the UWB beacon by this uwb_rc device.
- */
-static ssize_t ASIE_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;
-       char ie_buf[255];
-       int result, ie_len = 0;
-       const char *cur_ptr = buf;
-       struct uwb_ie_hdr *ie;
-
-       /* empty string means clear the ASIE. */
-       if (strlen(buf) <= 1) {
-               uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE);
-               return size;
-       }
-
-       /* if non-empty string, convert string of hex chars to binary. */
-       while (ie_len < sizeof(ie_buf)) {
-               int char_count;
-
-               if (sscanf(cur_ptr, " %02hhX %n",
-                               &(ie_buf[ie_len]), &char_count) > 0) {
-                       ++ie_len;
-                       /* skip chars read from cur_ptr. */
-                       cur_ptr += char_count;
-               } else {
-                       break;
-               }
-       }
-
-       /* validate IE length and type. */
-       if (ie_len < sizeof(struct uwb_ie_hdr)) {
-               dev_err(dev, "%s: Invalid ASIE size %d.\n", __func__, ie_len);
-               return -EINVAL;
-       }
-
-       ie = (struct uwb_ie_hdr *)ie_buf;
-       if (ie->element_id != UWB_APP_SPEC_IE) {
-               dev_err(dev, "%s: Invalid IE element type size = 0x%02X.\n",
-                               __func__, ie->element_id);
-               return -EINVAL;
-       }
-
-       /* bounds check length field from user. */
-       if (ie->length > (ie_len - sizeof(struct uwb_ie_hdr)))
-               ie->length = ie_len - sizeof(struct uwb_ie_hdr);
-
-       /*
-        * Valid ASIE received. Remove current ASIE then add the new one using
-        * uwb_rc_ie_add.
-        */
-       uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE);
-
-       result = uwb_rc_ie_add(rc, ie, ie->length + sizeof(struct uwb_ie_hdr));
-
-       return result >= 0 ? size : result;
-}
-static DEVICE_ATTR_RW(ASIE);
-
-static struct attribute *rc_attrs[] = {
-               &dev_attr_mac_address.attr,
-               &dev_attr_scan.attr,
-               &dev_attr_beacon.attr,
-               &dev_attr_ASIE.attr,
-               NULL,
-};
-
-static const struct attribute_group rc_attr_group = {
-       .attrs = rc_attrs,
-};
-
-/*
- * Registration of sysfs specific stuff
- */
-static int uwb_rc_sys_add(struct uwb_rc *rc)
-{
-       return sysfs_create_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
-}
-
-
-static void __uwb_rc_sys_rm(struct uwb_rc *rc)
-{
-       sysfs_remove_group(&rc->uwb_dev.dev.kobj, &rc_attr_group);
-}
-
-/**
- * uwb_rc_mac_addr_setup - get an RC's EUI-48 address or set it
- * @rc:  the radio controller.
- *
- * If the EUI-48 address is 00:00:00:00:00:00 or FF:FF:FF:FF:FF:FF
- * then a random locally administered EUI-48 is generated and set on
- * the device.  The probability of address collisions is sufficiently
- * unlikely (1/2^40 = 9.1e-13) that they're not checked for.
- */
-static
-int uwb_rc_mac_addr_setup(struct uwb_rc *rc)
-{
-       int result;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_dev *uwb_dev = &rc->uwb_dev;
-       char devname[UWB_ADDR_STRSIZE];
-       struct uwb_mac_addr addr;
-
-       result = uwb_rc_mac_addr_get(rc, &addr);
-       if (result < 0) {
-               dev_err(dev, "cannot retrieve UWB EUI-48 address: %d\n", result);
-               return result;
-       }
-
-       if (uwb_mac_addr_unset(&addr) || uwb_mac_addr_bcast(&addr)) {
-               addr.data[0] = 0x02; /* locally administered and unicast */
-               get_random_bytes(&addr.data[1], sizeof(addr.data)-1);
-
-               result = uwb_rc_mac_addr_set(rc, &addr);
-               if (result < 0) {
-                       uwb_mac_addr_print(devname, sizeof(devname), &addr);
-                       dev_err(dev, "cannot set EUI-48 address %s: %d\n",
-                               devname, result);
-                       return result;
-               }
-       }
-       uwb_dev->mac_addr = addr;
-       return 0;
-}
-
-
-
-static int uwb_rc_setup(struct uwb_rc *rc)
-{
-       int result;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       result = uwb_radio_setup(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot setup UWB radio: %d\n", result);
-               goto error;
-       }
-       result = uwb_rc_mac_addr_setup(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot setup UWB MAC address: %d\n", result);
-               goto error;
-       }
-       result = uwb_rc_dev_addr_assign(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot assign UWB DevAddr: %d\n", result);
-               goto error;
-       }
-       result = uwb_rc_ie_setup(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot setup IE subsystem: %d\n", result);
-               goto error_ie_setup;
-       }
-       result = uwb_rsv_setup(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot setup reservation subsystem: %d\n", result);
-               goto error_rsv_setup;
-       }
-       uwb_dbg_add_rc(rc);
-       return 0;
-
-error_rsv_setup:
-       uwb_rc_ie_release(rc);
-error_ie_setup:
-error:
-       return result;
-}
-
-
-/**
- * Register a new UWB radio controller
- *
- * Did you call uwb_rc_init() on your rc?
- *
- * We assume that this is being called with a > 0 refcount on
- * it [through ops->{get|put}_device(). We'll take our own, though.
- *
- * @parent_dev is our real device, the one that provides the actual UWB device
- */
-int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv)
-{
-       int result;
-       struct device *dev;
-       char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE];
-
-       rc->index = uwb_rc_new_index();
-
-       dev = &rc->uwb_dev.dev;
-       dev_set_name(dev, "uwb%d", rc->index);
-
-       rc->priv = priv;
-
-       init_waitqueue_head(&rc->uwbd.wq);
-       INIT_LIST_HEAD(&rc->uwbd.event_list);
-       spin_lock_init(&rc->uwbd.event_list_lock);
-
-       uwbd_start(rc);
-
-       result = rc->start(rc);
-       if (result < 0)
-               goto error_rc_start;
-
-       result = uwb_rc_setup(rc);
-       if (result < 0) {
-               dev_err(dev, "cannot setup UWB radio controller: %d\n", result);
-               goto error_rc_setup;
-       }
-
-       result = uwb_dev_add(&rc->uwb_dev, parent_dev, rc);
-       if (result < 0 && result != -EADDRNOTAVAIL)
-               goto error_dev_add;
-
-       result = uwb_rc_sys_add(rc);
-       if (result < 0) {
-               dev_err(parent_dev, "cannot register UWB radio controller "
-                       "dev attributes: %d\n", result);
-               goto error_sys_add;
-       }
-
-       uwb_mac_addr_print(macbuf, sizeof(macbuf), &rc->uwb_dev.mac_addr);
-       uwb_dev_addr_print(devbuf, sizeof(devbuf), &rc->uwb_dev.dev_addr);
-       dev_info(dev,
-                "new uwb radio controller (mac %s dev %s) on %s %s\n",
-                macbuf, devbuf, parent_dev->bus->name, dev_name(parent_dev));
-       rc->ready = 1;
-       return 0;
-
-error_sys_add:
-       uwb_dev_rm(&rc->uwb_dev);
-error_dev_add:
-error_rc_setup:
-       rc->stop(rc);
-error_rc_start:
-       uwbd_stop(rc);
-       return result;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_add);
-
-
-static int uwb_dev_offair_helper(struct device *dev, void *priv)
-{
-       struct uwb_dev *uwb_dev = to_uwb_dev(dev);
-
-       return __uwb_dev_offair(uwb_dev, uwb_dev->rc);
-}
-
-/*
- * Remove a Radio Controller; stop beaconing/scanning, disconnect all children
- */
-void uwb_rc_rm(struct uwb_rc *rc)
-{
-       rc->ready = 0;
-
-       uwb_dbg_del_rc(rc);
-       uwb_rsv_remove_all(rc);
-       uwb_radio_shutdown(rc);
-
-       rc->stop(rc);
-
-       uwbd_stop(rc);
-       uwb_rc_neh_destroy(rc);
-
-       uwb_dev_lock(&rc->uwb_dev);
-       rc->priv = NULL;
-       rc->cmd = NULL;
-       uwb_dev_unlock(&rc->uwb_dev);
-       mutex_lock(&rc->uwb_beca.mutex);
-       uwb_dev_for_each(rc, uwb_dev_offair_helper, NULL);
-       __uwb_rc_sys_rm(rc);
-       mutex_unlock(&rc->uwb_beca.mutex);
-       uwb_rsv_cleanup(rc);
-       uwb_beca_release(rc);
-       uwb_dev_rm(&rc->uwb_dev);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_rm);
-
-static int find_rc_try_get(struct device *dev, const void *data)
-{
-       const struct uwb_rc *target_rc = data;
-       struct uwb_rc *rc = dev_get_drvdata(dev);
-
-       if (rc == NULL) {
-               WARN_ON(1);
-               return 0;
-       }
-       if (rc == target_rc) {
-               if (rc->ready == 0)
-                       return 0;
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-/**
- * Given a radio controller descriptor, validate and refcount it
- *
- * @returns NULL if the rc does not exist or is quiescing; the ptr to
- *               it otherwise.
- */
-struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *target_rc)
-{
-       struct device *dev;
-       struct uwb_rc *rc = NULL;
-
-       dev = class_find_device(&uwb_rc_class, NULL, target_rc,
-                               find_rc_try_get);
-       if (dev) {
-               rc = dev_get_drvdata(dev);
-               __uwb_rc_get(rc);
-               put_device(dev);
-       }
-
-       return rc;
-}
-EXPORT_SYMBOL_GPL(__uwb_rc_try_get);
-
-/*
- * RC get for external refcount acquirers...
- *
- * Increments the refcount of the device and it's backend modules
- */
-static inline struct uwb_rc *uwb_rc_get(struct uwb_rc *rc)
-{
-       if (rc->ready == 0)
-               return NULL;
-       uwb_dev_get(&rc->uwb_dev);
-       return rc;
-}
-
-static int find_rc_grandpa(struct device *dev, const void *data)
-{
-       const struct device *grandpa_dev = data;
-       struct uwb_rc *rc = dev_get_drvdata(dev);
-
-       if (rc->uwb_dev.dev.parent->parent == grandpa_dev) {
-               rc = uwb_rc_get(rc);
-               return 1;
-       }
-       return 0;
-}
-
-/**
- * Locate and refcount a radio controller given a common grand-parent
- *
- * @grandpa_dev  Pointer to the 'grandparent' device structure.
- * @returns NULL If the rc does not exist or is quiescing; the ptr to
- *               it otherwise, properly referenced.
- *
- * The Radio Control interface (or the UWB Radio Controller) is always
- * an interface of a device. The parent is the interface, the
- * grandparent is the device that encapsulates the interface.
- *
- * There is no need to lock around as the "grandpa" would be
- * refcounted by the target, and to remove the referemes, the
- * uwb_rc_class->sem would have to be taken--we hold it, ergo we
- * should be safe.
- */
-struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev)
-{
-       struct device *dev;
-       struct uwb_rc *rc = NULL;
-
-       dev = class_find_device(&uwb_rc_class, NULL, grandpa_dev,
-                               find_rc_grandpa);
-       if (dev) {
-               rc = dev_get_drvdata(dev);
-               put_device(dev);
-       }
-
-       return rc;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa);
-
-/**
- * Find a radio controller by device address
- *
- * @returns the pointer to the radio controller, properly referenced
- */
-static int find_rc_dev(struct device *dev, const void *data)
-{
-       const struct uwb_dev_addr *addr = data;
-       struct uwb_rc *rc = dev_get_drvdata(dev);
-
-       if (rc == NULL) {
-               WARN_ON(1);
-               return 0;
-       }
-       if (!uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, addr)) {
-               rc = uwb_rc_get(rc);
-               return 1;
-       }
-       return 0;
-}
-
-struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr)
-{
-       struct device *dev;
-       struct uwb_rc *rc = NULL;
-
-       dev = class_find_device(&uwb_rc_class, NULL, addr, find_rc_dev);
-       if (dev) {
-               rc = dev_get_drvdata(dev);
-               put_device(dev);
-       }
-
-       return rc;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_get_by_dev);
-
-/**
- * Drop a reference on a radio controller
- *
- * This is the version that should be done by entities external to the
- * UWB Radio Control stack (ie: clients of the API).
- */
-void uwb_rc_put(struct uwb_rc *rc)
-{
-       __uwb_rc_put(rc);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_put);
diff --git a/drivers/uwb/neh.c b/drivers/uwb/neh.c
deleted file mode 100644 (file)
index 1695584..0000000
+++ /dev/null
@@ -1,606 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * WUSB Wire Adapter: Radio Control Interface (WUSB[8])
- * Notification and Event Handling
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * The RC interface of the Host Wire Adapter (USB dongle) or WHCI PCI
- * card delivers a stream of notifications and events to the
- * notification end event endpoint or area. This code takes care of
- * getting a buffer with that data, breaking it up in separate
- * notifications and events and then deliver those.
- *
- * Events are answers to commands and they carry a context ID that
- * associates them to the command. Notifications are that,
- * notifications, they come out of the blue and have a context ID of
- * zero. Think of the context ID kind of like a handler. The
- * uwb_rc_neh_* code deals with managing context IDs.
- *
- * This is why you require a handle to operate on a UWB host. When you
- * open a handle a context ID is assigned to you.
- *
- * So, as it is done is:
- *
- * 1. Add an event handler [uwb_rc_neh_add()] (assigns a ctx id)
- * 2. Issue command [rc->cmd(rc, ...)]
- * 3. Arm the timeout timer [uwb_rc_neh_arm()]
- * 4, Release the reference to the neh [uwb_rc_neh_put()]
- * 5. Wait for the callback
- * 6. Command result (RCEB) is passed to the callback
- *
- * If (2) fails, you should remove the handle [uwb_rc_neh_rm()]
- * instead of arming the timer.
- *
- * Handles are for using in *serialized* code, single thread.
- *
- * When the notification/event comes, the IRQ handler/endpoint
- * callback passes the data read to uwb_rc_neh_grok() which will break
- * it up in a discrete series of events, look up who is listening for
- * them and execute the pertinent callbacks.
- *
- * If the reader detects an error while reading the data stream, call
- * uwb_rc_neh_error().
- *
- * CONSTRAINTS/ASSUMPTIONS:
- *
- * - Most notifications/events are small (less thank .5k), copying
- *   around is ok.
- *
- * - Notifications/events are ALWAYS smaller than PAGE_SIZE
- *
- * - Notifications/events always come in a single piece (ie: a buffer
- *   will always contain entire notifications/events).
- *
- * - we cannot know in advance how long each event is (because they
- *   lack a length field in their header--smart move by the standards
- *   body, btw). So we need a facility to get the event size given the
- *   header. This is what the EST code does (notif/Event Size
- *   Tables), check nest.c--as well, you can associate the size to
- *   the handle [w/ neh->extra_size()].
- *
- * - Most notifications/events are fixed size; only a few are variable
- *   size (NEST takes care of that).
- *
- * - Listeners of events expect them, so they usually provide a
- *   buffer, as they know the size. Listeners to notifications don't,
- *   so we allocate their buffers dynamically.
- */
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-/*
- * UWB Radio Controller Notification/Event Handle
- *
- * Represents an entity waiting for an event coming from the UWB Radio
- * Controller with a given context id (context) and type (evt_type and
- * evt). On reception of the notification/event, the callback (cb) is
- * called with the event.
- *
- * If the timer expires before the event is received, the callback is
- * called with -ETIMEDOUT as the event size.
- */
-struct uwb_rc_neh {
-       struct kref kref;
-
-       struct uwb_rc *rc;
-       u8 evt_type;
-       __le16 evt;
-       u8 context;
-       u8 completed;
-       uwb_rc_cmd_cb_f cb;
-       void *arg;
-
-       struct timer_list timer;
-       struct list_head list_node;
-};
-
-static void uwb_rc_neh_timer(struct timer_list *t);
-
-static void uwb_rc_neh_release(struct kref *kref)
-{
-       struct uwb_rc_neh *neh = container_of(kref, struct uwb_rc_neh, kref);
-
-       kfree(neh);
-}
-
-static void uwb_rc_neh_get(struct uwb_rc_neh *neh)
-{
-       kref_get(&neh->kref);
-}
-
-/**
- * uwb_rc_neh_put - release reference to a neh
- * @neh: the neh
- */
-void uwb_rc_neh_put(struct uwb_rc_neh *neh)
-{
-       kref_put(&neh->kref, uwb_rc_neh_release);
-}
-
-
-/**
- * Assigns @neh a context id from @rc's pool
- *
- * @rc:            UWB Radio Controller descriptor; @rc->neh_lock taken
- * @neh:    Notification/Event Handle
- * @returns 0 if context id was assigned ok; < 0 errno on error (if
- *         all the context IDs are taken).
- *
- * (assumes @wa is locked).
- *
- * NOTE: WUSB spec reserves context ids 0x00 for notifications and
- *      0xff is invalid, so they must not be used. Initialization
- *      fills up those two in the bitmap so they are not allocated.
- *
- * We spread the allocation around to reduce the possibility of two
- * consecutive opened @neh's getting the same context ID assigned (to
- * avoid surprises with late events that timed out long time ago). So
- * first we search from where @rc->ctx_roll is, if not found, we
- * search from zero.
- */
-static
-int __uwb_rc_ctx_get(struct uwb_rc *rc, struct uwb_rc_neh *neh)
-{
-       int result;
-       result = find_next_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX,
-                                   rc->ctx_roll++);
-       if (result < UWB_RC_CTX_MAX)
-               goto found;
-       result = find_first_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX);
-       if (result < UWB_RC_CTX_MAX)
-               goto found;
-       return -ENFILE;
-found:
-       set_bit(result, rc->ctx_bm);
-       neh->context = result;
-       return 0;
-}
-
-
-/** Releases @neh's context ID back to @rc (@rc->neh_lock is locked). */
-static
-void __uwb_rc_ctx_put(struct uwb_rc *rc, struct uwb_rc_neh *neh)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       if (neh->context == 0)
-               return;
-       if (test_bit(neh->context, rc->ctx_bm) == 0) {
-               dev_err(dev, "context %u not set in bitmap\n",
-                       neh->context);
-               WARN_ON(1);
-       }
-       clear_bit(neh->context, rc->ctx_bm);
-       neh->context = 0;
-}
-
-/**
- * uwb_rc_neh_add - add a neh for a radio controller command
- * @rc:             the radio controller
- * @cmd:            the radio controller command
- * @expected_type:  the type of the expected response event
- * @expected_event: the expected event ID
- * @cb:             callback for when the event is received
- * @arg:            argument for the callback
- *
- * Creates a neh and adds it to the list of those waiting for an
- * event.  A context ID will be assigned to the command.
- */
-struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
-                                 u8 expected_type, u16 expected_event,
-                                 uwb_rc_cmd_cb_f cb, void *arg)
-{
-       int result;
-       unsigned long flags;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_neh *neh;
-
-       neh = kzalloc(sizeof(*neh), GFP_KERNEL);
-       if (neh == NULL) {
-               result = -ENOMEM;
-               goto error_kzalloc;
-       }
-
-       kref_init(&neh->kref);
-       INIT_LIST_HEAD(&neh->list_node);
-       timer_setup(&neh->timer, uwb_rc_neh_timer, 0);
-
-       neh->rc = rc;
-       neh->evt_type = expected_type;
-       neh->evt = cpu_to_le16(expected_event);
-       neh->cb = cb;
-       neh->arg = arg;
-
-       spin_lock_irqsave(&rc->neh_lock, flags);
-       result = __uwb_rc_ctx_get(rc, neh);
-       if (result >= 0) {
-               cmd->bCommandContext = neh->context;
-               list_add_tail(&neh->list_node, &rc->neh_list);
-               uwb_rc_neh_get(neh);
-       }
-       spin_unlock_irqrestore(&rc->neh_lock, flags);
-       if (result < 0)
-               goto error_ctx_get;
-
-       return neh;
-
-error_ctx_get:
-       kfree(neh);
-error_kzalloc:
-       dev_err(dev, "cannot open handle to radio controller: %d\n", result);
-       return ERR_PTR(result);
-}
-
-static void __uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
-{
-       __uwb_rc_ctx_put(rc, neh);
-       list_del(&neh->list_node);
-}
-
-/**
- * uwb_rc_neh_rm - remove a neh.
- * @rc:  the radio controller
- * @neh: the neh to remove
- *
- * Remove an active neh immediately instead of waiting for the event
- * (or a time out).
- */
-void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&rc->neh_lock, flags);
-       __uwb_rc_neh_rm(rc, neh);
-       spin_unlock_irqrestore(&rc->neh_lock, flags);
-
-       del_timer_sync(&neh->timer);
-       uwb_rc_neh_put(neh);
-}
-
-/**
- * uwb_rc_neh_arm - arm an event handler timeout timer
- *
- * @rc:     UWB Radio Controller
- * @neh:    Notification/event handler for @rc
- *
- * The timer is only armed if the neh is active.
- */
-void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&rc->neh_lock, flags);
-       if (neh->context)
-               mod_timer(&neh->timer,
-                         jiffies + msecs_to_jiffies(UWB_RC_CMD_TIMEOUT_MS));
-       spin_unlock_irqrestore(&rc->neh_lock, flags);
-}
-
-static void uwb_rc_neh_cb(struct uwb_rc_neh *neh, struct uwb_rceb *rceb, size_t size)
-{
-       (*neh->cb)(neh->rc, neh->arg, rceb, size);
-       uwb_rc_neh_put(neh);
-}
-
-static bool uwb_rc_neh_match(struct uwb_rc_neh *neh, const struct uwb_rceb *rceb)
-{
-       return neh->evt_type == rceb->bEventType
-               && neh->evt == rceb->wEvent
-               && neh->context == rceb->bEventContext;
-}
-
-/**
- * Find the handle waiting for a RC Radio Control Event
- *
- * @rc:         UWB Radio Controller
- * @rceb:       Pointer to the RCEB buffer
- * @event_size: Pointer to the size of the RCEB buffer. Might be
- *              adjusted to take into account the @neh->extra_size
- *              settings.
- *
- * If the listener has no buffer (NULL buffer), one is allocated for
- * the right size (the amount of data received). @neh->ptr will point
- * to the event payload, which always starts with a 'struct
- * uwb_rceb'. kfree() it when done.
- */
-static
-struct uwb_rc_neh *uwb_rc_neh_lookup(struct uwb_rc *rc,
-                                    const struct uwb_rceb *rceb)
-{
-       struct uwb_rc_neh *neh = NULL, *h;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rc->neh_lock, flags);
-
-       list_for_each_entry(h, &rc->neh_list, list_node) {
-               if (uwb_rc_neh_match(h, rceb)) {
-                       neh = h;
-                       break;
-               }
-       }
-
-       if (neh)
-               __uwb_rc_neh_rm(rc, neh);
-
-       spin_unlock_irqrestore(&rc->neh_lock, flags);
-
-       return neh;
-}
-
-
-/*
- * Process notifications coming from the radio control interface
- *
- * @rc:    UWB Radio Control Interface descriptor
- * @neh:   Notification/Event Handler @neh->ptr points to
- *         @uwb_evt->buffer.
- *
- * This function is called by the event/notif handling subsystem when
- * notifications arrive (hwarc_probe() arms a notification/event handle
- * that calls back this function for every received notification; this
- * function then will rearm itself).
- *
- * Notification data buffers are dynamically allocated by the NEH
- * handling code in neh.c [uwb_rc_neh_lookup()]. What is actually
- * allocated is space to contain the notification data.
- *
- * Buffers are prefixed with a Radio Control Event Block (RCEB) as
- * defined by the WUSB Wired-Adapter Radio Control interface. We
- * just use it for the notification code.
- *
- * On each case statement we just transcode endianess of the different
- * fields. We declare a pointer to a RCI definition of an event, and
- * then to a UWB definition of the same event (which are the same,
- * remember). Event if we use different pointers
- */
-static
-void uwb_rc_notif(struct uwb_rc *rc, struct uwb_rceb *rceb, ssize_t size)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_event *uwb_evt;
-
-       if (size == -ESHUTDOWN)
-               return;
-       if (size < 0) {
-               dev_err(dev, "ignoring event with error code %zu\n",
-                       size);
-               return;
-       }
-
-       uwb_evt = kzalloc(sizeof(*uwb_evt), GFP_ATOMIC);
-       if (unlikely(uwb_evt == NULL)) {
-               dev_err(dev, "no memory to queue event 0x%02x/%04x/%02x\n",
-                       rceb->bEventType, le16_to_cpu(rceb->wEvent),
-                       rceb->bEventContext);
-               return;
-       }
-       uwb_evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */
-       uwb_evt->ts_jiffies = jiffies;
-       uwb_evt->type = UWB_EVT_TYPE_NOTIF;
-       uwb_evt->notif.size = size;
-       uwb_evt->notif.rceb = rceb;
-
-       uwbd_event_queue(uwb_evt);
-}
-
-static void uwb_rc_neh_grok_event(struct uwb_rc *rc, struct uwb_rceb *rceb, size_t size)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_neh *neh;
-       struct uwb_rceb *notif;
-       unsigned long flags;
-
-       if (rceb->bEventContext == 0) {
-               notif = kmalloc(size, GFP_ATOMIC);
-               if (notif) {
-                       memcpy(notif, rceb, size);
-                       uwb_rc_notif(rc, notif, size);
-               } else
-                       dev_err(dev, "event 0x%02x/%04x/%02x (%zu bytes): no memory\n",
-                               rceb->bEventType, le16_to_cpu(rceb->wEvent),
-                               rceb->bEventContext, size);
-       } else {
-               neh = uwb_rc_neh_lookup(rc, rceb);
-               if (neh) {
-                       spin_lock_irqsave(&rc->neh_lock, flags);
-                       /* to guard against a timeout */
-                       neh->completed = 1;
-                       del_timer(&neh->timer);
-                       spin_unlock_irqrestore(&rc->neh_lock, flags);
-                       uwb_rc_neh_cb(neh, rceb, size);
-               } else
-                       dev_warn(dev, "event 0x%02x/%04x/%02x (%zu bytes): nobody cared\n",
-                                rceb->bEventType, le16_to_cpu(rceb->wEvent),
-                                rceb->bEventContext, size);
-       }
-}
-
-/**
- * Given a buffer with one or more UWB RC events/notifications, break
- * them up and dispatch them.
- *
- * @rc:              UWB Radio Controller
- * @buf:      Buffer with the stream of notifications/events
- * @buf_size: Amount of data in the buffer
- *
- * Note each notification/event starts always with a 'struct
- * uwb_rceb', so the minimum size if 4 bytes.
- *
- * The device may pass us events formatted differently than expected.
- * These are first filtered, potentially creating a new event in a new
- * memory location. If a new event is created by the filter it is also
- * freed here.
- *
- * For each notif/event, tries to guess the size looking at the EST
- * tables, then looks for a neh that is waiting for that event and if
- * found, copies the payload to the neh's buffer and calls it back. If
- * not, the data is ignored.
- *
- * Note that if we can't find a size description in the EST tables, we
- * still might find a size in the 'neh' handle in uwb_rc_neh_lookup().
- *
- * Assumptions:
- *
- *   @rc->neh_lock is NOT taken
- *
- * We keep track of various sizes here:
- * size:      contains the size of the buffer that is processed for the
- *            incoming event. this buffer may contain events that are not
- *            formatted as WHCI.
- * real_size: the actual space taken by this event in the buffer.
- *            We need to keep track of the real size of an event to be able to
- *            advance the buffer correctly.
- * event_size: the size of the event as expected by the core layer
- *            [OR] the size of the event after filtering. if the filtering
- *            created a new event in a new memory location then this is
- *            effectively the size of a new event buffer
- */
-void uwb_rc_neh_grok(struct uwb_rc *rc, void *buf, size_t buf_size)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       void *itr;
-       struct uwb_rceb *rceb;
-       size_t size, real_size, event_size;
-       int needtofree;
-
-       itr = buf;
-       size = buf_size;
-       while (size > 0) {
-               if (size < sizeof(*rceb)) {
-                       dev_err(dev, "not enough data in event buffer to "
-                               "process incoming events (%zu left, minimum is "
-                               "%zu)\n", size, sizeof(*rceb));
-                       break;
-               }
-
-               rceb = itr;
-               if (rc->filter_event) {
-                       needtofree = rc->filter_event(rc, &rceb, size,
-                                                     &real_size, &event_size);
-                       if (needtofree < 0 && needtofree != -ENOANO) {
-                               dev_err(dev, "BUG: Unable to filter event "
-                                       "(0x%02x/%04x/%02x) from "
-                                       "device. \n", rceb->bEventType,
-                                       le16_to_cpu(rceb->wEvent),
-                                       rceb->bEventContext);
-                               break;
-                       }
-               } else
-                       needtofree = -ENOANO;
-               /* do real processing if there was no filtering or the
-                * filtering didn't act */
-               if (needtofree == -ENOANO) {
-                       ssize_t ret = uwb_est_find_size(rc, rceb, size);
-                       if (ret < 0)
-                               break;
-                       if (ret > size) {
-                               dev_err(dev, "BUG: hw sent incomplete event "
-                                       "0x%02x/%04x/%02x (%zd bytes), only got "
-                                       "%zu bytes. We don't handle that.\n",
-                                       rceb->bEventType, le16_to_cpu(rceb->wEvent),
-                                       rceb->bEventContext, ret, size);
-                               break;
-                       }
-                       real_size = event_size = ret;
-               }
-               uwb_rc_neh_grok_event(rc, rceb, event_size);
-
-               if (needtofree == 1)
-                       kfree(rceb);
-
-               itr += real_size;
-               size -= real_size;
-       }
-}
-EXPORT_SYMBOL_GPL(uwb_rc_neh_grok);
-
-
-/**
- * The entity that reads from the device notification/event channel has
- * detected an error.
- *
- * @rc:    UWB Radio Controller
- * @error: Errno error code
- *
- */
-void uwb_rc_neh_error(struct uwb_rc *rc, int error)
-{
-       struct uwb_rc_neh *neh;
-       unsigned long flags;
-
-       for (;;) {
-               spin_lock_irqsave(&rc->neh_lock, flags);
-               if (list_empty(&rc->neh_list)) {
-                       spin_unlock_irqrestore(&rc->neh_lock, flags);
-                       break;
-               }
-               neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node);
-               __uwb_rc_neh_rm(rc, neh);
-               spin_unlock_irqrestore(&rc->neh_lock, flags);
-
-               del_timer_sync(&neh->timer);
-               uwb_rc_neh_cb(neh, NULL, error);
-       }
-}
-EXPORT_SYMBOL_GPL(uwb_rc_neh_error);
-
-
-static void uwb_rc_neh_timer(struct timer_list *t)
-{
-       struct uwb_rc_neh *neh = from_timer(neh, t, timer);
-       struct uwb_rc *rc = neh->rc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rc->neh_lock, flags);
-       if (neh->completed) {
-               spin_unlock_irqrestore(&rc->neh_lock, flags);
-               return;
-       }
-       if (neh->context)
-               __uwb_rc_neh_rm(rc, neh);
-       else
-               neh = NULL;
-       spin_unlock_irqrestore(&rc->neh_lock, flags);
-
-       if (neh)
-               uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT);
-}
-
-/** Initializes the @rc's neh subsystem
- */
-void uwb_rc_neh_create(struct uwb_rc *rc)
-{
-       spin_lock_init(&rc->neh_lock);
-       INIT_LIST_HEAD(&rc->neh_list);
-       set_bit(0, rc->ctx_bm);         /* 0 is reserved (see [WUSB] table 8-65) */
-       set_bit(0xff, rc->ctx_bm);      /* and 0xff is invalid */
-       rc->ctx_roll = 1;
-}
-
-
-/** Release's the @rc's neh subsystem */
-void uwb_rc_neh_destroy(struct uwb_rc *rc)
-{
-       unsigned long flags;
-       struct uwb_rc_neh *neh;
-
-       for (;;) {
-               spin_lock_irqsave(&rc->neh_lock, flags);
-               if (list_empty(&rc->neh_list)) {
-                       spin_unlock_irqrestore(&rc->neh_lock, flags);
-                       break;
-               }
-               neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node);
-               __uwb_rc_neh_rm(rc, neh);
-               spin_unlock_irqrestore(&rc->neh_lock, flags);
-
-               del_timer_sync(&neh->timer);
-               uwb_rc_neh_put(neh);
-       }
-}
diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c
deleted file mode 100644 (file)
index 765fd42..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB PAL support.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/debugfs.h>
-#include <linux/uwb.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-/**
- * uwb_pal_init - initialize a UWB PAL
- * @pal: the PAL to initialize
- */
-void uwb_pal_init(struct uwb_pal *pal)
-{
-       INIT_LIST_HEAD(&pal->node);
-}
-EXPORT_SYMBOL_GPL(uwb_pal_init);
-
-/**
- * uwb_pal_register - register a UWB PAL
- * @pal: the PAL
- *
- * The PAL must be initialized with uwb_pal_init().
- */
-int uwb_pal_register(struct uwb_pal *pal)
-{
-       struct uwb_rc *rc = pal->rc;
-       int ret;
-
-       if (pal->device) {
-               /* create a link to the uwb_rc in the PAL device's directory. */
-               ret = sysfs_create_link(&pal->device->kobj,
-                                       &rc->uwb_dev.dev.kobj, "uwb_rc");
-               if (ret < 0)
-                       return ret;
-               /* create a link to the PAL in the UWB device's directory. */
-               ret = sysfs_create_link(&rc->uwb_dev.dev.kobj,
-                                       &pal->device->kobj, pal->name);
-               if (ret < 0) {
-                       sysfs_remove_link(&pal->device->kobj, "uwb_rc");
-                       return ret;
-               }
-       }
-
-       pal->debugfs_dir = uwb_dbg_create_pal_dir(pal);
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       list_add(&pal->node, &rc->pals);
-       mutex_unlock(&rc->uwb_dev.mutex);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(uwb_pal_register);
-
-static int find_rc(struct device *dev, const void *data)
-{
-       const struct uwb_rc *target_rc = data;
-       struct uwb_rc *rc = dev_get_drvdata(dev);
-
-       if (rc == NULL) {
-               WARN_ON(1);
-               return 0;
-       }
-       if (rc == target_rc) {
-               if (rc->ready == 0)
-                       return 0;
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-/**
- * Given a radio controller descriptor see if it is registered.
- *
- * @returns false if the rc does not exist or is quiescing; true otherwise.
- */
-static bool uwb_rc_class_device_exists(struct uwb_rc *target_rc)
-{
-       struct device *dev;
-
-       dev = class_find_device(&uwb_rc_class, NULL, target_rc, find_rc);
-
-       put_device(dev);
-
-       return (dev != NULL);
-}
-
-/**
- * uwb_pal_unregister - unregister a UWB PAL
- * @pal: the PAL
- */
-void uwb_pal_unregister(struct uwb_pal *pal)
-{
-       struct uwb_rc *rc = pal->rc;
-
-       uwb_radio_stop(pal);
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       list_del(&pal->node);
-       mutex_unlock(&rc->uwb_dev.mutex);
-
-       debugfs_remove(pal->debugfs_dir);
-
-       if (pal->device) {
-               /* remove link to the PAL in the UWB device's directory. */
-               if (uwb_rc_class_device_exists(rc))
-                       sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name);
-
-               /* remove link to uwb_rc in the PAL device's directory. */
-               sysfs_remove_link(&pal->device->kobj, "uwb_rc");
-       }
-}
-EXPORT_SYMBOL_GPL(uwb_pal_unregister);
-
-/**
- * uwb_rc_pal_init - initialize the PAL related parts of a radio controller
- * @rc: the radio controller
- */
-void uwb_rc_pal_init(struct uwb_rc *rc)
-{
-       INIT_LIST_HEAD(&rc->pals);
-}
diff --git a/drivers/uwb/radio.c b/drivers/uwb/radio.c
deleted file mode 100644 (file)
index 240dd75..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB radio (channel) management.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/uwb.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-
-static int uwb_radio_select_channel(struct uwb_rc *rc)
-{
-       /*
-        * Default to channel 9 (BG1, TFC1) unless the user has
-        * selected a specific channel or there are no active PALs.
-        */
-       if (rc->active_pals == 0)
-               return -1;
-       if (rc->beaconing_forced)
-               return rc->beaconing_forced;
-       return 9;
-}
-
-
-/*
- * Notify all active PALs that the channel has changed.
- */
-static void uwb_radio_channel_changed(struct uwb_rc *rc, int channel)
-{
-       struct uwb_pal *pal;
-
-       list_for_each_entry(pal, &rc->pals, node) {
-               if (pal->channel && channel != pal->channel) {
-                       pal->channel = channel;
-                       if (pal->channel_changed)
-                               pal->channel_changed(pal, pal->channel);
-               }
-       }
-}
-
-/*
- * Change to a new channel and notify any active PALs of the new
- * channel.
- *
- * When stopping the radio, PALs need to be notified first so they can
- * terminate any active reservations.
- */
-static int uwb_radio_change_channel(struct uwb_rc *rc, int channel)
-{
-       int ret = 0;
-       struct device *dev = &rc->uwb_dev.dev;
-
-       dev_dbg(dev, "%s: channel = %d, rc->beaconing = %d\n", __func__,
-               channel, rc->beaconing);
-
-       if (channel == -1)
-               uwb_radio_channel_changed(rc, channel);
-
-       if (channel != rc->beaconing) {
-               if (rc->beaconing != -1 && channel != -1) {
-                       /*
-                        * FIXME: should signal the channel change
-                        * with a Channel Change IE.
-                        */
-                       ret = uwb_radio_change_channel(rc, -1);
-                       if (ret < 0)
-                               return ret;
-               }
-               ret = uwb_rc_beacon(rc, channel, 0);
-       }
-
-       if (channel != -1)
-               uwb_radio_channel_changed(rc, rc->beaconing);
-
-       return ret;
-}
-
-/**
- * uwb_radio_start - request that the radio be started
- * @pal: the PAL making the request.
- *
- * If the radio is not already active, a suitable channel is selected
- * and beacons are started.
- */
-int uwb_radio_start(struct uwb_pal *pal)
-{
-       struct uwb_rc *rc = pal->rc;
-       int ret = 0;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-
-       if (!pal->channel) {
-               pal->channel = -1;
-               rc->active_pals++;
-               ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
-       }
-
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(uwb_radio_start);
-
-/**
- * uwb_radio_stop - request that the radio be stopped.
- * @pal: the PAL making the request.
- *
- * Stops the radio if no other PAL is making use of it.
- */
-void uwb_radio_stop(struct uwb_pal *pal)
-{
-       struct uwb_rc *rc = pal->rc;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-
-       if (pal->channel) {
-               rc->active_pals--;
-               uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
-               pal->channel = 0;
-       }
-
-       mutex_unlock(&rc->uwb_dev.mutex);
-}
-EXPORT_SYMBOL_GPL(uwb_radio_stop);
-
-/*
- * uwb_radio_force_channel - force a specific channel to be used
- * @rc: the radio controller.
- * @channel: the channel to use; -1 to force the radio to stop; 0 to
- *   use the default channel selection algorithm.
- */
-int uwb_radio_force_channel(struct uwb_rc *rc, int channel)
-{
-       int ret = 0;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-
-       rc->beaconing_forced = channel;
-       ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc));
-
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return ret;
-}
-
-/*
- * uwb_radio_setup - setup the radio manager
- * @rc: the radio controller.
- *
- * The radio controller is reset to ensure it's in a known state
- * before it's used.
- */
-int uwb_radio_setup(struct uwb_rc *rc)
-{
-       return uwb_rc_reset(rc);
-}
-
-/*
- * uwb_radio_reset_state - reset any radio manager state
- * @rc: the radio controller.
- *
- * All internal radio manager state is reset to values corresponding
- * to a reset radio controller.
- */
-void uwb_radio_reset_state(struct uwb_rc *rc)
-{
-       struct uwb_pal *pal;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-
-       list_for_each_entry(pal, &rc->pals, node) {
-               if (pal->channel) {
-                       pal->channel = -1;
-                       if (pal->channel_changed)
-                               pal->channel_changed(pal, -1);
-               }
-       }
-
-       rc->beaconing = -1;
-       rc->scanning = -1;
-
-       mutex_unlock(&rc->uwb_dev.mutex);
-}
-
-/*
- * uwb_radio_shutdown - shutdown the radio manager
- * @rc: the radio controller.
- *
- * The radio controller is reset.
- */
-void uwb_radio_shutdown(struct uwb_rc *rc)
-{
-       uwb_radio_reset_state(rc);
-       uwb_rc_reset(rc);
-}
diff --git a/drivers/uwb/reset.c b/drivers/uwb/reset.c
deleted file mode 100644 (file)
index 8fc7c14..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * UWB basic command support and radio reset
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME:
- *
- *  - docs
- *
- *  - Now we are serializing (using the uwb_dev->mutex) the command
- *    execution; it should be parallelized as much as possible some
- *    day.
- */
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-/**
- * Command result codes (WUSB1.0[T8-69])
- */
-static
-const char *__strerror[] = {
-       "success",
-       "failure",
-       "hardware failure",
-       "no more slots",
-       "beacon is too large",
-       "invalid parameter",
-       "unsupported power level",
-       "time out (wa) or invalid ie data (whci)",
-       "beacon size exceeded",
-       "cancelled",
-       "invalid state",
-       "invalid size",
-       "ack not received",
-       "no more asie notification",
-};
-
-
-/** Return a string matching the given error code */
-const char *uwb_rc_strerror(unsigned code)
-{
-       if (code == 255)
-               return "time out";
-       if (code >= ARRAY_SIZE(__strerror))
-               return "unknown error";
-       return __strerror[code];
-}
-
-int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
-                    struct uwb_rccb *cmd, size_t cmd_size,
-                    u8 expected_type, u16 expected_event,
-                    uwb_rc_cmd_cb_f cb, void *arg)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_neh *neh;
-       int needtofree = 0;
-       int result;
-
-       uwb_dev_lock(&rc->uwb_dev);     /* Protect against rc->priv being removed */
-       if (rc->priv == NULL) {
-               uwb_dev_unlock(&rc->uwb_dev);
-               return -ESHUTDOWN;
-       }
-
-       if (rc->filter_cmd) {
-               needtofree = rc->filter_cmd(rc, &cmd, &cmd_size);
-               if (needtofree < 0 && needtofree != -ENOANO) {
-                       dev_err(dev, "%s: filter error: %d\n",
-                               cmd_name, needtofree);
-                       uwb_dev_unlock(&rc->uwb_dev);
-                       return needtofree;
-               }
-       }
-
-       neh = uwb_rc_neh_add(rc, cmd, expected_type, expected_event, cb, arg);
-       if (IS_ERR(neh)) {
-               result = PTR_ERR(neh);
-               uwb_dev_unlock(&rc->uwb_dev);
-               goto out;
-       }
-
-       result = rc->cmd(rc, cmd, cmd_size);
-       uwb_dev_unlock(&rc->uwb_dev);
-       if (result < 0)
-               uwb_rc_neh_rm(rc, neh);
-       else
-               uwb_rc_neh_arm(rc, neh);
-       uwb_rc_neh_put(neh);
-out:
-       if (needtofree == 1)
-               kfree(cmd);
-       return result < 0 ? result : 0;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_cmd_async);
-
-struct uwb_rc_cmd_done_params {
-       struct completion completion;
-       struct uwb_rceb *reply;
-       ssize_t reply_size;
-};
-
-static void uwb_rc_cmd_done(struct uwb_rc *rc, void *arg,
-                           struct uwb_rceb *reply, ssize_t reply_size)
-{
-       struct uwb_rc_cmd_done_params *p = (struct uwb_rc_cmd_done_params *)arg;
-
-       if (reply_size > 0) {
-               if (p->reply)
-                       reply_size = min(p->reply_size, reply_size);
-               else
-                       p->reply = kmalloc(reply_size, GFP_ATOMIC);
-
-               if (p->reply)
-                       memcpy(p->reply, reply, reply_size);
-               else
-                       reply_size = -ENOMEM;
-       }
-       p->reply_size = reply_size;
-       complete(&p->completion);
-}
-
-
-/**
- * Generic function for issuing commands to the Radio Control Interface
- *
- * @rc:       UWB Radio Control descriptor
- * @cmd_name: Name of the command being issued (for error messages)
- * @cmd:      Pointer to rccb structure containing the command;
- *            normally you embed this structure as the first member of
- *            the full command structure.
- * @cmd_size: Size of the whole command buffer pointed to by @cmd.
- * @reply:    Pointer to where to store the reply
- * @reply_size: @reply's size
- * @expected_type: Expected type in the return event
- * @expected_event: Expected event code in the return event
- * @preply:   Here a pointer to where the event data is received will
- *            be stored. Once done with the data, free with kfree().
- *
- * This function is generic; it works for commands that return a fixed
- * and known size or for commands that return a variable amount of data.
- *
- * If a buffer is provided, that is used, although it could be chopped
- * to the maximum size of the buffer. If the buffer is NULL, then one
- * be allocated in *preply with the whole contents of the reply.
- *
- * @rc needs to be referenced
- */
-static
-ssize_t __uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
-                    struct uwb_rccb *cmd, size_t cmd_size,
-                    struct uwb_rceb *reply, size_t reply_size,
-                    u8 expected_type, u16 expected_event,
-                    struct uwb_rceb **preply)
-{
-       ssize_t result = 0;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rc_cmd_done_params params;
-
-       init_completion(&params.completion);
-       params.reply = reply;
-       params.reply_size = reply_size;
-
-       result = uwb_rc_cmd_async(rc, cmd_name, cmd, cmd_size,
-                                 expected_type, expected_event,
-                                 uwb_rc_cmd_done, &params);
-       if (result)
-               return result;
-
-       wait_for_completion(&params.completion);
-
-       if (preply)
-               *preply = params.reply;
-
-       if (params.reply_size < 0)
-               dev_err(dev, "%s: confirmation event 0x%02x/%04x/%02x "
-                       "reception failed: %d\n", cmd_name,
-                       expected_type, expected_event, cmd->bCommandContext,
-                       (int)params.reply_size);
-       return params.reply_size;
-}
-
-
-/**
- * Generic function for issuing commands to the Radio Control Interface
- *
- * @rc:       UWB Radio Control descriptor
- * @cmd_name: Name of the command being issued (for error messages)
- * @cmd:      Pointer to rccb structure containing the command;
- *            normally you embed this structure as the first member of
- *            the full command structure.
- * @cmd_size: Size of the whole command buffer pointed to by @cmd.
- * @reply:    Pointer to the beginning of the confirmation event
- *            buffer. Normally bigger than an 'struct hwarc_rceb'.
- *            You need to fill out reply->bEventType and reply->wEvent (in
- *            cpu order) as the function will use them to verify the
- *            confirmation event.
- * @reply_size: Size of the reply buffer
- *
- * The function checks that the length returned in the reply is at
- * least as big as @reply_size; if not, it will be deemed an error and
- * -EIO returned.
- *
- * @rc needs to be referenced
- */
-ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
-                  struct uwb_rccb *cmd, size_t cmd_size,
-                  struct uwb_rceb *reply, size_t reply_size)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       ssize_t result;
-
-       result = __uwb_rc_cmd(rc, cmd_name,
-                             cmd, cmd_size, reply, reply_size,
-                             reply->bEventType, reply->wEvent, NULL);
-
-       if (result > 0 && result < reply_size) {
-               dev_err(dev, "%s: not enough data returned for decoding reply "
-                       "(%zu bytes received vs at least %zu needed)\n",
-                       cmd_name, result, reply_size);
-               result = -EIO;
-       }
-       return result;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_cmd);
-
-
-/**
- * Generic function for issuing commands to the Radio Control
- * Interface that return an unknown amount of data
- *
- * @rc:       UWB Radio Control descriptor
- * @cmd_name: Name of the command being issued (for error messages)
- * @cmd:      Pointer to rccb structure containing the command;
- *            normally you embed this structure as the first member of
- *            the full command structure.
- * @cmd_size: Size of the whole command buffer pointed to by @cmd.
- * @expected_type: Expected type in the return event
- * @expected_event: Expected event code in the return event
- * @preply:   Here a pointer to where the event data is received will
- *            be stored. Once done with the data, free with kfree().
- *
- * The function checks that the length returned in the reply is at
- * least as big as a 'struct uwb_rceb *'; if not, it will be deemed an
- * error and -EIO returned.
- *
- * @rc needs to be referenced
- */
-ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name,
-                   struct uwb_rccb *cmd, size_t cmd_size,
-                   u8 expected_type, u16 expected_event,
-                   struct uwb_rceb **preply)
-{
-       return __uwb_rc_cmd(rc, cmd_name, cmd, cmd_size, NULL, 0,
-                           expected_type, expected_event, preply);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_vcmd);
-
-
-/**
- * Reset a UWB Host Controller (and all radio settings)
- *
- * @rc:      Host Controller descriptor
- * @returns: 0 if ok, < 0 errno code on error
- *
- * We put the command on kmalloc'ed memory as some arches cannot do
- * USB from the stack. The reply event is copied from an stage buffer,
- * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
- */
-int uwb_rc_reset(struct uwb_rc *rc)
-{
-       int result = -ENOMEM;
-       struct uwb_rc_evt_confirm reply;
-       struct uwb_rccb *cmd;
-       size_t cmd_size = sizeof(*cmd);
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               goto error_kzalloc;
-       cmd->bCommandType = UWB_RC_CET_GENERAL;
-       cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET);
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_RESET;
-       result = uwb_rc_cmd(rc, "RESET", cmd, cmd_size,
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(&rc->uwb_dev.dev,
-                       "RESET: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
-               result = -EIO;
-       }
-error_cmd:
-       kfree(cmd);
-error_kzalloc:
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return result;
-}
-
-int uwbd_msg_handle_reset(struct uwb_event *evt)
-{
-       struct uwb_rc *rc = evt->rc;
-       int ret;
-
-       dev_info(&rc->uwb_dev.dev, "resetting radio controller\n");
-       ret = rc->reset(rc);
-       if (ret < 0) {
-               dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret);
-               goto error;
-       }
-       return 0;
-error:
-       /* Nothing can be done except try the reset again. Wait a bit
-          to avoid reset loops during probe() or remove(). */
-       msleep(1000);
-       uwb_rc_reset_all(rc);
-       return ret;
-}
-
-/**
- * uwb_rc_reset_all - request a reset of the radio controller and PALs
- * @rc: the radio controller of the hardware device to be reset.
- *
- * The full hardware reset of the radio controller and all the PALs
- * will be scheduled.
- */
-void uwb_rc_reset_all(struct uwb_rc *rc)
-{
-       struct uwb_event *evt;
-
-       evt = kzalloc(sizeof(struct uwb_event), GFP_ATOMIC);
-       if (unlikely(evt == NULL))
-               return;
-
-       evt->rc = __uwb_rc_get(rc);     /* will be put by uwbd's uwbd_event_handle() */
-       evt->ts_jiffies = jiffies;
-       evt->type = UWB_EVT_TYPE_MSG;
-       evt->message = UWB_EVT_MSG_RESET;
-
-       uwbd_event_queue(evt);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_reset_all);
-
-void uwb_rc_pre_reset(struct uwb_rc *rc)
-{
-       rc->stop(rc);
-       uwbd_flush(rc);
-
-       uwb_radio_reset_state(rc);
-       uwb_rsv_remove_all(rc);
-}
-EXPORT_SYMBOL_GPL(uwb_rc_pre_reset);
-
-int uwb_rc_post_reset(struct uwb_rc *rc)
-{
-       int ret;
-
-       ret = rc->start(rc);
-       if (ret)
-               goto out;
-       ret = uwb_rc_mac_addr_set(rc, &rc->uwb_dev.mac_addr);
-       if (ret)
-               goto out;
-       ret = uwb_rc_dev_addr_set(rc, &rc->uwb_dev.dev_addr);
-       if (ret)
-               goto out;
-out:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(uwb_rc_post_reset);
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c
deleted file mode 100644 (file)
index ec924de..0000000
+++ /dev/null
@@ -1,1000 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB reservation management.
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/uwb.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/export.h>
-
-#include "uwb-internal.h"
-
-static void uwb_rsv_timer(struct timer_list *t);
-
-static const char *rsv_states[] = {
-       [UWB_RSV_STATE_NONE]                 = "none            ",
-       [UWB_RSV_STATE_O_INITIATED]          = "o initiated     ",
-       [UWB_RSV_STATE_O_PENDING]            = "o pending       ",
-       [UWB_RSV_STATE_O_MODIFIED]           = "o modified      ",
-       [UWB_RSV_STATE_O_ESTABLISHED]        = "o established   ",
-       [UWB_RSV_STATE_O_TO_BE_MOVED]        = "o to be moved   ",
-       [UWB_RSV_STATE_O_MOVE_EXPANDING]     = "o move expanding",
-       [UWB_RSV_STATE_O_MOVE_COMBINING]     = "o move combining",
-       [UWB_RSV_STATE_O_MOVE_REDUCING]      = "o move reducing ",
-       [UWB_RSV_STATE_T_ACCEPTED]           = "t accepted      ",
-       [UWB_RSV_STATE_T_CONFLICT]           = "t conflict      ",
-       [UWB_RSV_STATE_T_PENDING]            = "t pending       ",
-       [UWB_RSV_STATE_T_DENIED]             = "t denied        ",
-       [UWB_RSV_STATE_T_RESIZED]            = "t resized       ",
-       [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = "t expanding acc ",
-       [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = "t expanding conf",
-       [UWB_RSV_STATE_T_EXPANDING_PENDING]  = "t expanding pend",
-       [UWB_RSV_STATE_T_EXPANDING_DENIED]   = "t expanding den ",
-};
-
-static const char *rsv_types[] = {
-       [UWB_DRP_TYPE_ALIEN_BP] = "alien-bp",
-       [UWB_DRP_TYPE_HARD]     = "hard",
-       [UWB_DRP_TYPE_SOFT]     = "soft",
-       [UWB_DRP_TYPE_PRIVATE]  = "private",
-       [UWB_DRP_TYPE_PCA]      = "pca",
-};
-
-bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv)
-{
-       static const bool has_two_drp_ies[] = {
-               [UWB_RSV_STATE_O_INITIATED]               = false,
-               [UWB_RSV_STATE_O_PENDING]                 = false,
-               [UWB_RSV_STATE_O_MODIFIED]                = false,
-               [UWB_RSV_STATE_O_ESTABLISHED]             = false,
-               [UWB_RSV_STATE_O_TO_BE_MOVED]             = false,
-               [UWB_RSV_STATE_O_MOVE_COMBINING]          = false,
-               [UWB_RSV_STATE_O_MOVE_REDUCING]           = false,
-               [UWB_RSV_STATE_O_MOVE_EXPANDING]          = true,
-               [UWB_RSV_STATE_T_ACCEPTED]                = false,
-               [UWB_RSV_STATE_T_CONFLICT]                = false,
-               [UWB_RSV_STATE_T_PENDING]                 = false,
-               [UWB_RSV_STATE_T_DENIED]                  = false,
-               [UWB_RSV_STATE_T_RESIZED]                 = false,
-               [UWB_RSV_STATE_T_EXPANDING_ACCEPTED]      = true,
-               [UWB_RSV_STATE_T_EXPANDING_CONFLICT]      = true,
-               [UWB_RSV_STATE_T_EXPANDING_PENDING]       = true,
-               [UWB_RSV_STATE_T_EXPANDING_DENIED]        = true,
-       };
-
-       return has_two_drp_ies[rsv->state];
-}
-
-/**
- * uwb_rsv_state_str - return a string for a reservation state
- * @state: the reservation state.
- */
-const char *uwb_rsv_state_str(enum uwb_rsv_state state)
-{
-       if (state < UWB_RSV_STATE_NONE || state >= UWB_RSV_STATE_LAST)
-               return "unknown";
-       return rsv_states[state];
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_state_str);
-
-/**
- * uwb_rsv_type_str - return a string for a reservation type
- * @type: the reservation type
- */
-const char *uwb_rsv_type_str(enum uwb_drp_type type)
-{
-       if (type < UWB_DRP_TYPE_ALIEN_BP || type > UWB_DRP_TYPE_PCA)
-               return "invalid";
-       return rsv_types[type];
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_type_str);
-
-void uwb_rsv_dump(char *text, struct uwb_rsv *rsv)
-{
-       struct device *dev = &rsv->rc->uwb_dev.dev;
-       struct uwb_dev_addr devaddr;
-       char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
-
-       uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
-       if (rsv->target.type == UWB_RSV_TARGET_DEV)
-               devaddr = rsv->target.dev->dev_addr;
-       else
-               devaddr = rsv->target.devaddr;
-       uwb_dev_addr_print(target, sizeof(target), &devaddr);
-
-       dev_dbg(dev, "rsv %s %s -> %s: %s\n",
-               text, owner, target, uwb_rsv_state_str(rsv->state));
-}
-
-static void uwb_rsv_release(struct kref *kref)
-{
-       struct uwb_rsv *rsv = container_of(kref, struct uwb_rsv, kref);
-
-       kfree(rsv);
-}
-
-void uwb_rsv_get(struct uwb_rsv *rsv)
-{
-       kref_get(&rsv->kref);
-}
-
-void uwb_rsv_put(struct uwb_rsv *rsv)
-{
-       kref_put(&rsv->kref, uwb_rsv_release);
-}
-
-/*
- * Get a free stream index for a reservation.
- *
- * If the target is a DevAddr (e.g., a WUSB cluster reservation) then
- * the stream is allocated from a pool of per-RC stream indexes,
- * otherwise a unique stream index for the target is selected.
- */
-static int uwb_rsv_get_stream(struct uwb_rsv *rsv)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct device *dev = &rc->uwb_dev.dev;
-       unsigned long *streams_bm;
-       int stream;
-
-       switch (rsv->target.type) {
-       case UWB_RSV_TARGET_DEV:
-               streams_bm = rsv->target.dev->streams;
-               break;
-       case UWB_RSV_TARGET_DEVADDR:
-               streams_bm = rc->uwb_dev.streams;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       stream = find_first_zero_bit(streams_bm, UWB_NUM_STREAMS);
-       if (stream >= UWB_NUM_STREAMS) {
-               dev_err(dev, "%s: no available stream found\n", __func__);
-               return -EBUSY;
-       }
-
-       rsv->stream = stream;
-       set_bit(stream, streams_bm);
-
-       dev_dbg(dev, "get stream %d\n", rsv->stream);
-
-       return 0;
-}
-
-static void uwb_rsv_put_stream(struct uwb_rsv *rsv)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct device *dev = &rc->uwb_dev.dev;
-       unsigned long *streams_bm;
-
-       switch (rsv->target.type) {
-       case UWB_RSV_TARGET_DEV:
-               streams_bm = rsv->target.dev->streams;
-               break;
-       case UWB_RSV_TARGET_DEVADDR:
-               streams_bm = rc->uwb_dev.streams;
-               break;
-       default:
-               return;
-       }
-
-       clear_bit(rsv->stream, streams_bm);
-
-       dev_dbg(dev, "put stream %d\n", rsv->stream);
-}
-
-void uwb_rsv_backoff_win_timer(struct timer_list *t)
-{
-       struct uwb_drp_backoff_win *bow = from_timer(bow, t, timer);
-       struct uwb_rc *rc = container_of(bow, struct uwb_rc, bow);
-       struct device *dev = &rc->uwb_dev.dev;
-
-       bow->can_reserve_extra_mases = true;
-       if (bow->total_expired <= 4) {
-               bow->total_expired++;
-       } else {
-               /* after 4 backoff window has expired we can exit from
-                * the backoff procedure */
-               bow->total_expired = 0;
-               bow->window = UWB_DRP_BACKOFF_WIN_MIN >> 1;
-       }
-       dev_dbg(dev, "backoff_win_timer total_expired=%d, n=%d\n", bow->total_expired, bow->n);
-
-       /* try to relocate all the "to be moved" relocations */
-       uwb_rsv_handle_drp_avail_change(rc);
-}
-
-void uwb_rsv_backoff_win_increment(struct uwb_rc *rc)
-{
-       struct uwb_drp_backoff_win *bow = &rc->bow;
-       struct device *dev = &rc->uwb_dev.dev;
-       unsigned timeout_us;
-
-       dev_dbg(dev, "backoff_win_increment: window=%d\n", bow->window);
-
-       bow->can_reserve_extra_mases = false;
-
-       if((bow->window << 1) == UWB_DRP_BACKOFF_WIN_MAX)
-               return;
-
-       bow->window <<= 1;
-       bow->n = prandom_u32() & (bow->window - 1);
-       dev_dbg(dev, "new_window=%d, n=%d\n", bow->window, bow->n);
-
-       /* reset the timer associated variables */
-       timeout_us = bow->n * UWB_SUPERFRAME_LENGTH_US;
-       bow->total_expired = 0;
-       mod_timer(&bow->timer, jiffies + usecs_to_jiffies(timeout_us));
-}
-
-static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv)
-{
-       int sframes = UWB_MAX_LOST_BEACONS;
-
-       /*
-        * Multicast reservations can become established within 1
-        * super frame and should not be terminated if no response is
-        * received.
-        */
-       if (rsv->state == UWB_RSV_STATE_NONE) {
-               sframes = 0;
-       } else if (rsv->is_multicast) {
-               if (rsv->state == UWB_RSV_STATE_O_INITIATED
-                   || rsv->state == UWB_RSV_STATE_O_MOVE_EXPANDING
-                   || rsv->state == UWB_RSV_STATE_O_MOVE_COMBINING
-                   || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING)
-                       sframes = 1;
-               if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED)
-                       sframes = 0;
-
-       }
-
-       if (sframes > 0) {
-               /*
-                * Add an additional 2 superframes to account for the
-                * time to send the SET DRP IE command.
-                */
-               unsigned timeout_us = (sframes + 2) * UWB_SUPERFRAME_LENGTH_US;
-               mod_timer(&rsv->timer, jiffies + usecs_to_jiffies(timeout_us));
-       } else
-               del_timer(&rsv->timer);
-}
-
-/*
- * Update a reservations state, and schedule an update of the
- * transmitted DRP IEs.
- */
-static void uwb_rsv_state_update(struct uwb_rsv *rsv,
-                                enum uwb_rsv_state new_state)
-{
-       rsv->state = new_state;
-       rsv->ie_valid = false;
-
-       uwb_rsv_dump("SU", rsv);
-
-       uwb_rsv_stroke_timer(rsv);
-       uwb_rsv_sched_update(rsv->rc);
-}
-
-static void uwb_rsv_callback(struct uwb_rsv *rsv)
-{
-       if (rsv->callback)
-               rsv->callback(rsv);
-}
-
-void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state)
-{
-       struct uwb_rsv_move *mv = &rsv->mv;
-
-       if (rsv->state == new_state) {
-               switch (rsv->state) {
-               case UWB_RSV_STATE_O_ESTABLISHED:
-               case UWB_RSV_STATE_O_MOVE_EXPANDING:
-               case UWB_RSV_STATE_O_MOVE_COMBINING:
-               case UWB_RSV_STATE_O_MOVE_REDUCING:
-               case UWB_RSV_STATE_T_ACCEPTED:
-               case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
-               case UWB_RSV_STATE_T_RESIZED:
-               case UWB_RSV_STATE_NONE:
-                       uwb_rsv_stroke_timer(rsv);
-                       break;
-               default:
-                       /* Expecting a state transition so leave timer
-                          as-is. */
-                       break;
-               }
-               return;
-       }
-
-       uwb_rsv_dump("SC", rsv);
-
-       switch (new_state) {
-       case UWB_RSV_STATE_NONE:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE);
-               uwb_rsv_remove(rsv);
-               uwb_rsv_callback(rsv);
-               break;
-       case UWB_RSV_STATE_O_INITIATED:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_INITIATED);
-               break;
-       case UWB_RSV_STATE_O_PENDING:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_PENDING);
-               break;
-       case UWB_RSV_STATE_O_MODIFIED:
-               /* in the companion there are the MASes to drop */
-               bitmap_andnot(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS);
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MODIFIED);
-               break;
-       case UWB_RSV_STATE_O_ESTABLISHED:
-               if (rsv->state == UWB_RSV_STATE_O_MODIFIED
-                   || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING) {
-                       uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
-                       rsv->needs_release_companion_mas = false;
-               }
-               uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-               uwb_rsv_callback(rsv);
-               break;
-       case UWB_RSV_STATE_O_MOVE_EXPANDING:
-               rsv->needs_release_companion_mas = true;
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
-               break;
-       case UWB_RSV_STATE_O_MOVE_COMBINING:
-               rsv->needs_release_companion_mas = false;
-               uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas);
-               bitmap_or(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS);
-               rsv->mas.safe   += mv->companion_mas.safe;
-               rsv->mas.unsafe += mv->companion_mas.unsafe;
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
-               break;
-       case UWB_RSV_STATE_O_MOVE_REDUCING:
-               bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS);
-               rsv->needs_release_companion_mas = true;
-               rsv->mas.safe   = mv->final_mas.safe;
-               rsv->mas.unsafe = mv->final_mas.unsafe;
-               bitmap_copy(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS);
-               bitmap_copy(rsv->mas.unsafe_bm, mv->final_mas.unsafe_bm, UWB_NUM_MAS);
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
-               break;
-       case UWB_RSV_STATE_T_ACCEPTED:
-       case UWB_RSV_STATE_T_RESIZED:
-               rsv->needs_release_companion_mas = false;
-               uwb_drp_avail_reserve(rsv->rc, &rsv->mas);
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_ACCEPTED);
-               uwb_rsv_callback(rsv);
-               break;
-       case UWB_RSV_STATE_T_DENIED:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_DENIED);
-               break;
-       case UWB_RSV_STATE_T_CONFLICT:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_CONFLICT);
-               break;
-       case UWB_RSV_STATE_T_PENDING:
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_PENDING);
-               break;
-       case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
-               rsv->needs_release_companion_mas = true;
-               uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas);
-               uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
-               break;
-       default:
-               dev_err(&rsv->rc->uwb_dev.dev, "unhandled state: %s (%d)\n",
-                       uwb_rsv_state_str(new_state), new_state);
-       }
-}
-
-static void uwb_rsv_handle_timeout_work(struct work_struct *work)
-{
-       struct uwb_rsv *rsv = container_of(work, struct uwb_rsv,
-                                          handle_timeout_work);
-       struct uwb_rc *rc = rsv->rc;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       uwb_rsv_dump("TO", rsv);
-
-       switch (rsv->state) {
-       case UWB_RSV_STATE_O_INITIATED:
-               if (rsv->is_multicast) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-                       goto unlock;
-               }
-               break;
-       case UWB_RSV_STATE_O_MOVE_EXPANDING:
-               if (rsv->is_multicast) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
-                       goto unlock;
-               }
-               break;
-       case UWB_RSV_STATE_O_MOVE_COMBINING:
-               if (rsv->is_multicast) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
-                       goto unlock;
-               }
-               break;
-       case UWB_RSV_STATE_O_MOVE_REDUCING:
-               if (rsv->is_multicast) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-                       goto unlock;
-               }
-               break;
-       case UWB_RSV_STATE_O_ESTABLISHED:
-               if (rsv->is_multicast)
-                       goto unlock;
-               break;
-       case UWB_RSV_STATE_T_EXPANDING_ACCEPTED:
-               /*
-                * The time out could be for the main or of the
-                * companion DRP, assume it's for the companion and
-                * drop that first.  A further time out is required to
-                * drop the main.
-                */
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
-               uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
-               goto unlock;
-       case UWB_RSV_STATE_NONE:
-               goto unlock;
-       default:
-               break;
-       }
-
-       uwb_rsv_remove(rsv);
-
-unlock:
-       mutex_unlock(&rc->rsvs_mutex);
-}
-
-static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc)
-{
-       struct uwb_rsv *rsv;
-
-       rsv = kzalloc(sizeof(struct uwb_rsv), GFP_KERNEL);
-       if (!rsv)
-               return NULL;
-
-       INIT_LIST_HEAD(&rsv->rc_node);
-       INIT_LIST_HEAD(&rsv->pal_node);
-       kref_init(&rsv->kref);
-       timer_setup(&rsv->timer, uwb_rsv_timer, 0);
-
-       rsv->rc = rc;
-       INIT_WORK(&rsv->handle_timeout_work, uwb_rsv_handle_timeout_work);
-
-       return rsv;
-}
-
-/**
- * uwb_rsv_create - allocate and initialize a UWB reservation structure
- * @rc: the radio controller
- * @cb: callback to use when the reservation completes or terminates
- * @pal_priv: data private to the PAL to be passed in the callback
- *
- * The callback is called when the state of the reservation changes from:
- *
- *   - pending to accepted
- *   - pending to denined
- *   - accepted to terminated
- *   - pending to terminated
- */
-struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb, void *pal_priv)
-{
-       struct uwb_rsv *rsv;
-
-       rsv = uwb_rsv_alloc(rc);
-       if (!rsv)
-               return NULL;
-
-       rsv->callback = cb;
-       rsv->pal_priv = pal_priv;
-
-       return rsv;
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_create);
-
-void uwb_rsv_remove(struct uwb_rsv *rsv)
-{
-       uwb_rsv_dump("RM", rsv);
-
-       if (rsv->state != UWB_RSV_STATE_NONE)
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-
-       if (rsv->needs_release_companion_mas)
-               uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
-       uwb_drp_avail_release(rsv->rc, &rsv->mas);
-
-       if (uwb_rsv_is_owner(rsv))
-               uwb_rsv_put_stream(rsv);
-
-       uwb_dev_put(rsv->owner);
-       if (rsv->target.type == UWB_RSV_TARGET_DEV)
-               uwb_dev_put(rsv->target.dev);
-
-       list_del_init(&rsv->rc_node);
-       uwb_rsv_put(rsv);
-}
-
-/**
- * uwb_rsv_destroy - free a UWB reservation structure
- * @rsv: the reservation to free
- *
- * The reservation must already be terminated.
- */
-void uwb_rsv_destroy(struct uwb_rsv *rsv)
-{
-       uwb_rsv_put(rsv);
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_destroy);
-
-/**
- * usb_rsv_establish - start a reservation establishment
- * @rsv: the reservation
- *
- * The PAL should fill in @rsv's owner, target, type, max_mas,
- * min_mas, max_interval and is_multicast fields.  If the target is a
- * uwb_dev it must be referenced.
- *
- * The reservation's callback will be called when the reservation is
- * accepted, denied or times out.
- */
-int uwb_rsv_establish(struct uwb_rsv *rsv)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct uwb_mas_bm available;
-       struct device *dev = &rc->uwb_dev.dev;
-       int ret;
-
-       mutex_lock(&rc->rsvs_mutex);
-       ret = uwb_rsv_get_stream(rsv);
-       if (ret) {
-               dev_err(dev, "%s: uwb_rsv_get_stream failed: %d\n",
-                       __func__, ret);
-               goto out;
-       }
-
-       rsv->tiebreaker = prandom_u32() & 1;
-       /* get available mas bitmap */
-       uwb_drp_available(rc, &available);
-
-       ret = uwb_rsv_find_best_allocation(rsv, &available, &rsv->mas);
-       if (ret == UWB_RSV_ALLOC_NOT_FOUND) {
-               ret = -EBUSY;
-               uwb_rsv_put_stream(rsv);
-               dev_err(dev, "%s: uwb_rsv_find_best_allocation failed: %d\n",
-                       __func__, ret);
-               goto out;
-       }
-
-       ret = uwb_drp_avail_reserve_pending(rc, &rsv->mas);
-       if (ret != 0) {
-               uwb_rsv_put_stream(rsv);
-               dev_err(dev, "%s: uwb_drp_avail_reserve_pending failed: %d\n",
-                       __func__, ret);
-               goto out;
-       }
-
-       uwb_rsv_get(rsv);
-       list_add_tail(&rsv->rc_node, &rc->reservations);
-       rsv->owner = &rc->uwb_dev;
-       uwb_dev_get(rsv->owner);
-       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_INITIATED);
-out:
-       mutex_unlock(&rc->rsvs_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_establish);
-
-/**
- * uwb_rsv_modify - modify an already established reservation
- * @rsv: the reservation to modify
- * @max_mas: new maximum MAS to reserve
- * @min_mas: new minimum MAS to reserve
- * @max_interval: new max_interval to use
- *
- * FIXME: implement this once there are PALs that use it.
- */
-int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int max_interval)
-{
-       return -ENOSYS;
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_modify);
-
-/*
- * move an already established reservation (rc->rsvs_mutex must to be
- * taken when tis function is called)
- */
-int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available)
-{
-       struct uwb_rc *rc = rsv->rc;
-       struct uwb_drp_backoff_win *bow = &rc->bow;
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_rsv_move *mv;
-       int ret = 0;
-
-       if (bow->can_reserve_extra_mases == false)
-               return -EBUSY;
-
-       mv = &rsv->mv;
-
-       if (uwb_rsv_find_best_allocation(rsv, available, &mv->final_mas) == UWB_RSV_ALLOC_FOUND) {
-
-               if (!bitmap_equal(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS)) {
-                       /* We want to move the reservation */
-                       bitmap_andnot(mv->companion_mas.bm, mv->final_mas.bm, rsv->mas.bm, UWB_NUM_MAS);
-                       uwb_drp_avail_reserve_pending(rc, &mv->companion_mas);
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
-               }
-       } else {
-               dev_dbg(dev, "new allocation not found\n");
-       }
-
-       return ret;
-}
-
-/* It will try to move every reservation in state O_ESTABLISHED giving
- * to the MAS allocator algorithm an availability that is the real one
- * plus the allocation already established from the reservation. */
-void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc)
-{
-       struct uwb_drp_backoff_win *bow = &rc->bow;
-       struct uwb_rsv *rsv;
-       struct uwb_mas_bm mas;
-
-       if (bow->can_reserve_extra_mases == false)
-               return;
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED ||
-                   rsv->state == UWB_RSV_STATE_O_TO_BE_MOVED) {
-                       uwb_drp_available(rc, &mas);
-                       bitmap_or(mas.bm, mas.bm, rsv->mas.bm, UWB_NUM_MAS);
-                       uwb_rsv_try_move(rsv, &mas);
-               }
-       }
-
-}
-
-/**
- * uwb_rsv_terminate - terminate an established reservation
- * @rsv: the reservation to terminate
- *
- * A reservation is terminated by removing the DRP IE from the beacon,
- * the other end will consider the reservation to be terminated when
- * it does not see the DRP IE for at least mMaxLostBeacons.
- *
- * If applicable, the reference to the target uwb_dev will be released.
- */
-void uwb_rsv_terminate(struct uwb_rsv *rsv)
-{
-       struct uwb_rc *rc = rsv->rc;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       if (rsv->state != UWB_RSV_STATE_NONE)
-               uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-
-       mutex_unlock(&rc->rsvs_mutex);
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_terminate);
-
-/**
- * uwb_rsv_accept - accept a new reservation from a peer
- * @rsv:      the reservation
- * @cb:       call back for reservation changes
- * @pal_priv: data to be passed in the above call back
- *
- * Reservation requests from peers are denied unless a PAL accepts it
- * by calling this function.
- *
- * The PAL call uwb_rsv_destroy() for all accepted reservations before
- * calling uwb_pal_unregister().
- */
-void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv)
-{
-       uwb_rsv_get(rsv);
-
-       rsv->callback = cb;
-       rsv->pal_priv = pal_priv;
-       rsv->state    = UWB_RSV_STATE_T_ACCEPTED;
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_accept);
-
-/*
- * Is a received DRP IE for this reservation?
- */
-static bool uwb_rsv_match(struct uwb_rsv *rsv, struct uwb_dev *src,
-                         struct uwb_ie_drp *drp_ie)
-{
-       struct uwb_dev_addr *rsv_src;
-       int stream;
-
-       stream = uwb_ie_drp_stream_index(drp_ie);
-
-       if (rsv->stream != stream)
-               return false;
-
-       switch (rsv->target.type) {
-       case UWB_RSV_TARGET_DEVADDR:
-               return rsv->stream == stream;
-       case UWB_RSV_TARGET_DEV:
-               if (uwb_ie_drp_owner(drp_ie))
-                       rsv_src = &rsv->owner->dev_addr;
-               else
-                       rsv_src = &rsv->target.dev->dev_addr;
-               return uwb_dev_addr_cmp(&src->dev_addr, rsv_src) == 0;
-       }
-       return false;
-}
-
-static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc,
-                                         struct uwb_dev *src,
-                                         struct uwb_ie_drp *drp_ie)
-{
-       struct uwb_rsv *rsv;
-       struct uwb_pal *pal;
-       enum uwb_rsv_state state;
-
-       rsv = uwb_rsv_alloc(rc);
-       if (!rsv)
-               return NULL;
-
-       rsv->rc          = rc;
-       rsv->owner       = src;
-       uwb_dev_get(rsv->owner);
-       rsv->target.type = UWB_RSV_TARGET_DEV;
-       rsv->target.dev  = &rc->uwb_dev;
-       uwb_dev_get(&rc->uwb_dev);
-       rsv->type        = uwb_ie_drp_type(drp_ie);
-       rsv->stream      = uwb_ie_drp_stream_index(drp_ie);
-       uwb_drp_ie_to_bm(&rsv->mas, drp_ie);
-
-       /*
-        * See if any PALs are interested in this reservation. If not,
-        * deny the request.
-        */
-       rsv->state = UWB_RSV_STATE_T_DENIED;
-       mutex_lock(&rc->uwb_dev.mutex);
-       list_for_each_entry(pal, &rc->pals, node) {
-               if (pal->new_rsv)
-                       pal->new_rsv(pal, rsv);
-               if (rsv->state == UWB_RSV_STATE_T_ACCEPTED)
-                       break;
-       }
-       mutex_unlock(&rc->uwb_dev.mutex);
-
-       list_add_tail(&rsv->rc_node, &rc->reservations);
-       state = rsv->state;
-       rsv->state = UWB_RSV_STATE_NONE;
-
-       /* FIXME: do something sensible here */
-       if (state == UWB_RSV_STATE_T_ACCEPTED
-           && uwb_drp_avail_reserve_pending(rc, &rsv->mas) == -EBUSY) {
-               /* FIXME: do something sensible here */
-       } else {
-               uwb_rsv_set_state(rsv, state);
-       }
-
-       return rsv;
-}
-
-/**
- * uwb_rsv_get_usable_mas - get the bitmap of the usable MAS of a reservations
- * @rsv: the reservation.
- * @mas: returns the available MAS.
- *
- * The usable MAS of a reservation may be less than the negotiated MAS
- * if alien BPs are present.
- */
-void uwb_rsv_get_usable_mas(struct uwb_rsv *rsv, struct uwb_mas_bm *mas)
-{
-       bitmap_zero(mas->bm, UWB_NUM_MAS);
-       bitmap_andnot(mas->bm, rsv->mas.bm, rsv->rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
-}
-EXPORT_SYMBOL_GPL(uwb_rsv_get_usable_mas);
-
-/**
- * uwb_rsv_find - find a reservation for a received DRP IE.
- * @rc: the radio controller
- * @src: source of the DRP IE
- * @drp_ie: the DRP IE
- *
- * If the reservation cannot be found and the DRP IE is from a peer
- * attempting to establish a new reservation, create a new reservation
- * and add it to the list.
- */
-struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
-                            struct uwb_ie_drp *drp_ie)
-{
-       struct uwb_rsv *rsv;
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (uwb_rsv_match(rsv, src, drp_ie))
-                       return rsv;
-       }
-
-       if (uwb_ie_drp_owner(drp_ie))
-               return uwb_rsv_new_target(rc, src, drp_ie);
-
-       return NULL;
-}
-
-/*
- * Go through all the reservations and check for timeouts and (if
- * necessary) update their DRP IEs.
- *
- * FIXME: look at building the SET_DRP_IE command here rather than
- * having to rescan the list in uwb_rc_send_all_drp_ie().
- */
-static bool uwb_rsv_update_all(struct uwb_rc *rc)
-{
-       struct uwb_rsv *rsv, *t;
-       bool ie_updated = false;
-
-       list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
-               if (!rsv->ie_valid) {
-                       uwb_drp_ie_update(rsv);
-                       ie_updated = true;
-               }
-       }
-
-       return ie_updated;
-}
-
-void uwb_rsv_queue_update(struct uwb_rc *rc)
-{
-       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
-
-       queue_delayed_work(rc->rsv_workq, &rc->rsv_update_work, usecs_to_jiffies(delay_us));
-}
-
-/**
- * uwb_rsv_sched_update - schedule an update of the DRP IEs
- * @rc: the radio controller.
- *
- * To improve performance and ensure correctness with [ECMA-368] the
- * number of SET-DRP-IE commands that are done are limited.
- *
- * DRP IEs update come from two sources: DRP events from the hardware
- * which all occur at the beginning of the superframe ('syncronous'
- * events) and reservation establishment/termination requests from
- * PALs or timers ('asynchronous' events).
- *
- * A delayed work ensures that all the synchronous events result in
- * one SET-DRP-IE command.
- *
- * Additional logic (the set_drp_ie_pending and rsv_updated_postponed
- * flags) will prevent an asynchrous event starting a SET-DRP-IE
- * command if one is currently awaiting a response.
- *
- * FIXME: this does leave a window where an asynchrous event can delay
- * the SET-DRP-IE for a synchronous event by one superframe.
- */
-void uwb_rsv_sched_update(struct uwb_rc *rc)
-{
-       spin_lock_irq(&rc->rsvs_lock);
-       if (!delayed_work_pending(&rc->rsv_update_work)) {
-               if (rc->set_drp_ie_pending > 0) {
-                       rc->set_drp_ie_pending++;
-                       goto unlock;
-               }
-               uwb_rsv_queue_update(rc);
-       }
-unlock:
-       spin_unlock_irq(&rc->rsvs_lock);
-}
-
-/*
- * Update DRP IEs and, if necessary, the DRP Availability IE and send
- * the updated IEs to the radio controller.
- */
-static void uwb_rsv_update_work(struct work_struct *work)
-{
-       struct uwb_rc *rc = container_of(work, struct uwb_rc,
-                                        rsv_update_work.work);
-       bool ie_updated;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       ie_updated = uwb_rsv_update_all(rc);
-
-       if (!rc->drp_avail.ie_valid) {
-               uwb_drp_avail_ie_update(rc);
-               ie_updated = true;
-       }
-
-       if (ie_updated && (rc->set_drp_ie_pending == 0))
-               uwb_rc_send_all_drp_ie(rc);
-
-       mutex_unlock(&rc->rsvs_mutex);
-}
-
-static void uwb_rsv_alien_bp_work(struct work_struct *work)
-{
-       struct uwb_rc *rc = container_of(work, struct uwb_rc,
-                                        rsv_alien_bp_work.work);
-       struct uwb_rsv *rsv;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (rsv->type != UWB_DRP_TYPE_ALIEN_BP) {
-                       uwb_rsv_callback(rsv);
-               }
-       }
-
-       mutex_unlock(&rc->rsvs_mutex);
-}
-
-static void uwb_rsv_timer(struct timer_list *t)
-{
-       struct uwb_rsv *rsv = from_timer(rsv, t, timer);
-
-       queue_work(rsv->rc->rsv_workq, &rsv->handle_timeout_work);
-}
-
-/**
- * uwb_rsv_remove_all - remove all reservations
- * @rc: the radio controller
- *
- * A DRP IE update is not done.
- */
-void uwb_rsv_remove_all(struct uwb_rc *rc)
-{
-       struct uwb_rsv *rsv, *t;
-
-       mutex_lock(&rc->rsvs_mutex);
-       list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
-               if (rsv->state != UWB_RSV_STATE_NONE)
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-               del_timer_sync(&rsv->timer);
-       }
-       /* Cancel any postponed update. */
-       rc->set_drp_ie_pending = 0;
-       mutex_unlock(&rc->rsvs_mutex);
-
-       cancel_delayed_work_sync(&rc->rsv_update_work);
-       flush_workqueue(rc->rsv_workq);
-
-       mutex_lock(&rc->rsvs_mutex);
-       list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) {
-               uwb_rsv_remove(rsv);
-       }
-       mutex_unlock(&rc->rsvs_mutex);
-}
-
-void uwb_rsv_init(struct uwb_rc *rc)
-{
-       INIT_LIST_HEAD(&rc->reservations);
-       INIT_LIST_HEAD(&rc->cnflt_alien_list);
-       mutex_init(&rc->rsvs_mutex);
-       spin_lock_init(&rc->rsvs_lock);
-       INIT_DELAYED_WORK(&rc->rsv_update_work, uwb_rsv_update_work);
-       INIT_DELAYED_WORK(&rc->rsv_alien_bp_work, uwb_rsv_alien_bp_work);
-       rc->bow.can_reserve_extra_mases = true;
-       rc->bow.total_expired = 0;
-       rc->bow.window = UWB_DRP_BACKOFF_WIN_MIN >> 1;
-       timer_setup(&rc->bow.timer, uwb_rsv_backoff_win_timer, 0);
-
-       bitmap_complement(rc->uwb_dev.streams, rc->uwb_dev.streams, UWB_NUM_STREAMS);
-}
-
-int uwb_rsv_setup(struct uwb_rc *rc)
-{
-       char name[16];
-
-       snprintf(name, sizeof(name), "%s_rsvd", dev_name(&rc->uwb_dev.dev));
-       rc->rsv_workq = create_singlethread_workqueue(name);
-       if (rc->rsv_workq == NULL)
-               return -ENOMEM;
-
-       return 0;
-}
-
-void uwb_rsv_cleanup(struct uwb_rc *rc)
-{
-       uwb_rsv_remove_all(rc);
-       destroy_workqueue(rc->rsv_workq);
-}
diff --git a/drivers/uwb/scan.c b/drivers/uwb/scan.c
deleted file mode 100644 (file)
index ffc3f45..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Scanning management
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: docs
- * FIXME: there are issues here on how BEACON and SCAN on USB RCI deal
- *        with each other. Currently seems that START_BEACON while
- *        SCAN_ONLY will cancel the scan, so we need to update the
- *        state here. Clarification request sent by email on
- *        10/05/2005.
- *        10/28/2005 No clear answer heard--maybe we'll hack the API
- *                   so that when we start beaconing, if the HC is
- *                   scanning in a mode not compatible with beaconing
- *                   we just fail.
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include "uwb-internal.h"
-
-
-/**
- * Start/stop scanning in a radio controller
- *
- * @rc:      UWB Radio Controller
- * @channel: Channel to scan; encodings in WUSB1.0[Table 5.12]
- * @type:    Type of scanning to do.
- * @bpst_offset: value at which to start scanning (if type ==
- *                UWB_SCAN_ONLY_STARTTIME)
- * @returns: 0 if ok, < 0 errno code on error
- *
- * We put the command on kmalloc'ed memory as some arches cannot do
- * USB from the stack. The reply event is copied from an stage buffer,
- * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details.
- */
-int uwb_rc_scan(struct uwb_rc *rc,
-               unsigned channel, enum uwb_scan_type type,
-               unsigned bpst_offset)
-{
-       int result;
-       struct uwb_rc_cmd_scan *cmd;
-       struct uwb_rc_evt_confirm reply;
-
-       result = -ENOMEM;
-       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (cmd == NULL)
-               goto error_kzalloc;
-       mutex_lock(&rc->uwb_dev.mutex);
-       cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
-       cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SCAN);
-       cmd->bChannelNumber = channel;
-       cmd->bScanState = type;
-       cmd->wStartTime = cpu_to_le16(bpst_offset);
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_SCAN;
-       result = uwb_rc_cmd(rc, "SCAN", &cmd->rccb, sizeof(*cmd),
-                           &reply.rceb, sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(&rc->uwb_dev.dev,
-                       "SCAN: command execution failed: %s (%d)\n",
-                       uwb_rc_strerror(reply.bResultCode), reply.bResultCode);
-               result = -EIO;
-               goto error_cmd;
-       }
-       rc->scanning = channel;
-       rc->scan_type = type;
-error_cmd:
-       mutex_unlock(&rc->uwb_dev.mutex);
-       kfree(cmd);
-error_kzalloc:
-       return result;
-}
-
-/*
- * Print scanning state
- */
-static ssize_t uwb_rc_scan_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;
-       ssize_t result;
-
-       mutex_lock(&rc->uwb_dev.mutex);
-       result = sprintf(buf, "%d %d\n", rc->scanning, rc->scan_type);
-       mutex_unlock(&rc->uwb_dev.mutex);
-       return result;
-}
-
-/*
- *
- */
-static ssize_t uwb_rc_scan_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;
-       unsigned channel;
-       unsigned type;
-       unsigned bpst_offset = 0;
-       ssize_t result = -EINVAL;
-
-       result = sscanf(buf, "%u %u %u\n", &channel, &type, &bpst_offset);
-       if (result >= 2 && type < UWB_SCAN_TOP)
-               result = uwb_rc_scan(rc, channel, type, bpst_offset);
-
-       return result < 0 ? result : size;
-}
-
-/** Radio Control sysfs interface (declaration) */
-DEVICE_ATTR(scan, S_IRUGO | S_IWUSR, uwb_rc_scan_show, uwb_rc_scan_store);
diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c
deleted file mode 100644 (file)
index 0fdc380..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Bus for UWB Multi-interface Controller capabilities.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/sysfs.h>
-#include <linux/workqueue.h>
-#include <linux/module.h>
-#include <linux/uwb/umc.h>
-#include <linux/pci.h>
-
-static int umc_bus_pre_reset_helper(struct device *dev, void *data)
-{
-       int ret = 0;
-
-       if (dev->driver) {
-               struct umc_dev *umc = to_umc_dev(dev);
-               struct umc_driver *umc_drv = to_umc_driver(dev->driver);
-
-               if (umc_drv->pre_reset)
-                       ret = umc_drv->pre_reset(umc);
-               else
-                       device_release_driver(dev);
-       }
-       return ret;
-}
-
-static int umc_bus_post_reset_helper(struct device *dev, void *data)
-{
-       int ret = 0;
-
-       if (dev->driver) {
-               struct umc_dev *umc = to_umc_dev(dev);
-               struct umc_driver *umc_drv = to_umc_driver(dev->driver);
-
-               if (umc_drv->post_reset)
-                       ret = umc_drv->post_reset(umc);
-       } else
-               ret = device_attach(dev);
-
-       return ret;
-}
-
-/**
- * umc_controller_reset - reset the whole UMC controller
- * @umc: the UMC device for the radio controller.
- *
- * Drivers or all capabilities of the controller will have their
- * pre_reset methods called or be unbound from their device.  Then all
- * post_reset methods will be called or the drivers will be rebound.
- *
- * Radio controllers must provide pre_reset and post_reset methods and
- * reset the hardware in their start method.
- *
- * If this is called while a probe() or remove() is in progress it
- * will return -EAGAIN and not perform the reset.
- */
-int umc_controller_reset(struct umc_dev *umc)
-{
-       struct device *parent = umc->dev.parent;
-       int ret = 0;
-
-       if (!device_trylock(parent))
-               return -EAGAIN;
-       ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper);
-       if (ret >= 0)
-               ret = device_for_each_child(parent, parent, umc_bus_post_reset_helper);
-       device_unlock(parent);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(umc_controller_reset);
-
-/**
- * umc_match_pci_id - match a UMC driver to a UMC device's parent PCI device.
- * @umc_drv: umc driver with match_data pointing to a zero-terminated
- * table of pci_device_id's.
- * @umc: umc device whose parent is to be matched.
- */
-int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc)
-{
-       const struct pci_device_id *id_table = umc_drv->match_data;
-       struct pci_dev *pci;
-
-       if (!dev_is_pci(umc->dev.parent))
-               return 0;
-
-       pci = to_pci_dev(umc->dev.parent);
-       return pci_match_id(id_table, pci) != NULL;
-}
-EXPORT_SYMBOL_GPL(umc_match_pci_id);
-
-static int umc_bus_rescan_helper(struct device *dev, void *data)
-{
-       int ret = 0;
-
-       if (!dev->driver)
-               ret = device_attach(dev);
-
-       return ret;
-}
-
-static void umc_bus_rescan(struct device *parent)
-{
-       int err;
-
-       /*
-        * We can't use bus_rescan_devices() here as it deadlocks when
-        * it tries to retake the dev->parent semaphore.
-        */
-       err = device_for_each_child(parent, NULL, umc_bus_rescan_helper);
-       if (err < 0)
-               printk(KERN_WARNING "%s: rescan of bus failed: %d\n",
-                      KBUILD_MODNAME, err);
-}
-
-static int umc_bus_match(struct device *dev, struct device_driver *drv)
-{
-       struct umc_dev *umc = to_umc_dev(dev);
-       struct umc_driver *umc_driver = to_umc_driver(drv);
-
-       if (umc->cap_id == umc_driver->cap_id) {
-               if (umc_driver->match)
-                       return umc_driver->match(umc_driver, umc);
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-static int umc_device_probe(struct device *dev)
-{
-       struct umc_dev *umc;
-       struct umc_driver *umc_driver;
-       int err;
-
-       umc_driver = to_umc_driver(dev->driver);
-       umc = to_umc_dev(dev);
-
-       get_device(dev);
-       err = umc_driver->probe(umc);
-       if (err)
-               put_device(dev);
-       else
-               umc_bus_rescan(dev->parent);
-
-       return err;
-}
-
-static int umc_device_remove(struct device *dev)
-{
-       struct umc_dev *umc;
-       struct umc_driver *umc_driver;
-
-       umc_driver = to_umc_driver(dev->driver);
-       umc = to_umc_dev(dev);
-
-       umc_driver->remove(umc);
-       put_device(dev);
-       return 0;
-}
-
-static ssize_t capability_id_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct umc_dev *umc = to_umc_dev(dev);
-
-       return sprintf(buf, "0x%02x\n", umc->cap_id);
-}
-static DEVICE_ATTR_RO(capability_id);
-
-static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct umc_dev *umc = to_umc_dev(dev);
-
-       return sprintf(buf, "0x%04x\n", umc->version);
-}
-static DEVICE_ATTR_RO(version);
-
-static struct attribute *umc_dev_attrs[] = {
-       &dev_attr_capability_id.attr,
-       &dev_attr_version.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(umc_dev);
-
-struct bus_type umc_bus_type = {
-       .name           = "umc",
-       .match          = umc_bus_match,
-       .probe          = umc_device_probe,
-       .remove         = umc_device_remove,
-       .dev_groups     = umc_dev_groups,
-};
-EXPORT_SYMBOL_GPL(umc_bus_type);
-
-static int __init umc_bus_init(void)
-{
-       return bus_register(&umc_bus_type);
-}
-module_init(umc_bus_init);
-
-static void __exit umc_bus_exit(void)
-{
-       bus_unregister(&umc_bus_type);
-}
-module_exit(umc_bus_exit);
-
-MODULE_DESCRIPTION("UWB Multi-interface Controller capability bus");
-MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
-MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/umc-dev.c b/drivers/uwb/umc-dev.c
deleted file mode 100644 (file)
index c845ca4..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * UWB Multi-interface Controller device management.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/uwb/umc.h>
-
-static void umc_device_release(struct device *dev)
-{
-       struct umc_dev *umc = to_umc_dev(dev);
-
-       kfree(umc);
-}
-
-/**
- * umc_device_create - allocate a child UMC device
- * @parent: parent of the new UMC device.
- * @n:      index of the new device.
- *
- * The new UMC device will have a bus ID of the parent with '-n'
- * appended.
- */
-struct umc_dev *umc_device_create(struct device *parent, int n)
-{
-       struct umc_dev *umc;
-
-       umc = kzalloc(sizeof(struct umc_dev), GFP_KERNEL);
-       if (umc) {
-               dev_set_name(&umc->dev, "%s-%d", dev_name(parent), n);
-               umc->dev.parent  = parent;
-               umc->dev.bus     = &umc_bus_type;
-               umc->dev.release = umc_device_release;
-
-               umc->dev.dma_mask = parent->dma_mask;
-       }
-       return umc;
-}
-EXPORT_SYMBOL_GPL(umc_device_create);
-
-/**
- * umc_device_register - register a UMC device
- * @umc: pointer to the UMC device
- *
- * The memory resource for the UMC device is acquired and the device
- * registered with the system.
- */
-int umc_device_register(struct umc_dev *umc)
-{
-       int err;
-
-       err = request_resource(umc->resource.parent, &umc->resource);
-       if (err < 0) {
-               dev_err(&umc->dev, "can't allocate resource range %pR: %d\n",
-                       &umc->resource, err);
-               goto error_request_resource;
-       }
-
-       err = device_register(&umc->dev);
-       if (err < 0)
-               goto error_device_register;
-       return 0;
-
-error_device_register:
-       put_device(&umc->dev);
-       release_resource(&umc->resource);
-error_request_resource:
-       return err;
-}
-EXPORT_SYMBOL_GPL(umc_device_register);
-
-/**
- * umc_device_unregister - unregister a UMC device
- * @umc: pointer to the UMC device
- *
- * First we unregister the device, make sure the driver can do it's
- * resource release thing and then we try to release any left over
- * resources. We take a ref to the device, to make sure it doesn't
- * disappear under our feet.
- */
-void umc_device_unregister(struct umc_dev *umc)
-{
-       struct device *dev;
-       if (!umc)
-               return;
-       dev = get_device(&umc->dev);
-       device_unregister(&umc->dev);
-       release_resource(&umc->resource);
-       put_device(dev);
-}
-EXPORT_SYMBOL_GPL(umc_device_unregister);
diff --git a/drivers/uwb/umc-drv.c b/drivers/uwb/umc-drv.c
deleted file mode 100644 (file)
index b141d52..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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 <linux/uwb/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);
diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c
deleted file mode 100644 (file)
index 5457b6d..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Debug support
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- *
- * FIXME: doc
- */
-
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/notifier.h>
-#include <linux/device.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/seq_file.h>
-
-#include <linux/uwb/debug-cmd.h>
-
-#include "uwb-internal.h"
-
-/*
- * Debug interface
- *
- * Per radio controller debugfs files (in uwb/uwbN/):
- *
- * command: Flexible command interface (see <linux/uwb/debug-cmd.h>).
- *
- * reservations: information on reservations.
- *
- * accept: Set to true (Y or 1) to accept reservation requests from
- * peers.
- *
- * drp_avail: DRP availability information.
- */
-
-struct uwb_dbg {
-       struct uwb_pal pal;
-
-       bool accept;
-       struct list_head rsvs;
-
-       struct dentry *root_d;
-       struct dentry *command_f;
-       struct dentry *reservations_f;
-       struct dentry *accept_f;
-       struct dentry *drp_avail_f;
-       spinlock_t list_lock;
-};
-
-static struct dentry *root_dir;
-
-static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv)
-{
-       struct uwb_dbg *dbg = rsv->pal_priv;
-
-       uwb_rsv_dump("debug", rsv);
-
-       if (rsv->state == UWB_RSV_STATE_NONE) {
-               spin_lock(&dbg->list_lock);
-               list_del(&rsv->pal_node);
-               spin_unlock(&dbg->list_lock);
-               uwb_rsv_destroy(rsv);
-       }
-}
-
-static int cmd_rsv_establish(struct uwb_rc *rc,
-                            struct uwb_dbg_cmd_rsv_establish *cmd)
-{
-       struct uwb_mac_addr macaddr;
-       struct uwb_rsv *rsv;
-       struct uwb_dev *target;
-       int ret;
-
-       memcpy(&macaddr, cmd->target, sizeof(macaddr));
-       target = uwb_dev_get_by_macaddr(rc, &macaddr);
-       if (target == NULL)
-               return -ENODEV;
-
-       rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, rc->dbg);
-       if (rsv == NULL) {
-               uwb_dev_put(target);
-               return -ENOMEM;
-       }
-
-       rsv->target.type  = UWB_RSV_TARGET_DEV;
-       rsv->target.dev   = target;
-       rsv->type         = cmd->type;
-       rsv->max_mas      = cmd->max_mas;
-       rsv->min_mas      = cmd->min_mas;
-       rsv->max_interval = cmd->max_interval;
-
-       ret = uwb_rsv_establish(rsv);
-       if (ret)
-               uwb_rsv_destroy(rsv);
-       else {
-               spin_lock(&(rc->dbg)->list_lock);
-               list_add_tail(&rsv->pal_node, &rc->dbg->rsvs);
-               spin_unlock(&(rc->dbg)->list_lock);
-       }
-       return ret;
-}
-
-static int cmd_rsv_terminate(struct uwb_rc *rc,
-                            struct uwb_dbg_cmd_rsv_terminate *cmd)
-{
-       struct uwb_rsv *rsv, *found = NULL;
-       int i = 0;
-
-       spin_lock(&(rc->dbg)->list_lock);
-
-       list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) {
-               if (i == cmd->index) {
-                       found = rsv;
-                       uwb_rsv_get(found);
-                       break;
-               }
-               i++;
-       }
-
-       spin_unlock(&(rc->dbg)->list_lock);
-
-       if (!found)
-               return -EINVAL;
-
-       uwb_rsv_terminate(found);
-       uwb_rsv_put(found);
-
-       return 0;
-}
-
-static int cmd_ie_add(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_add)
-{
-       return uwb_rc_ie_add(rc,
-                            (const struct uwb_ie_hdr *) ie_to_add->data,
-                            ie_to_add->len);
-}
-
-static int cmd_ie_rm(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_rm)
-{
-       return uwb_rc_ie_rm(rc, ie_to_rm->data[0]);
-}
-
-static ssize_t command_write(struct file *file, const char __user *buf,
-                        size_t len, loff_t *off)
-{
-       struct uwb_rc *rc = file->private_data;
-       struct uwb_dbg_cmd cmd;
-       int ret = 0;
-       
-       if (len != sizeof(struct uwb_dbg_cmd))
-               return -EINVAL;
-
-       if (copy_from_user(&cmd, buf, len) != 0)
-               return -EFAULT;
-
-       switch (cmd.type) {
-       case UWB_DBG_CMD_RSV_ESTABLISH:
-               ret = cmd_rsv_establish(rc, &cmd.rsv_establish);
-               break;
-       case UWB_DBG_CMD_RSV_TERMINATE:
-               ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate);
-               break;
-       case UWB_DBG_CMD_IE_ADD:
-               ret = cmd_ie_add(rc, &cmd.ie_add);
-               break;
-       case UWB_DBG_CMD_IE_RM:
-               ret = cmd_ie_rm(rc, &cmd.ie_rm);
-               break;
-       case UWB_DBG_CMD_RADIO_START:
-               ret = uwb_radio_start(&rc->dbg->pal);
-               break;
-       case UWB_DBG_CMD_RADIO_STOP:
-               uwb_radio_stop(&rc->dbg->pal);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return ret < 0 ? ret : len;
-}
-
-static const struct file_operations command_fops = {
-       .open   = simple_open,
-       .write  = command_write,
-       .read   = NULL,
-       .llseek = no_llseek,
-       .owner  = THIS_MODULE,
-};
-
-static int reservations_show(struct seq_file *s, void *p)
-{
-       struct uwb_rc *rc = s->private;
-       struct uwb_rsv *rsv;
-
-       mutex_lock(&rc->rsvs_mutex);
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               struct uwb_dev_addr devaddr;
-               char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
-               bool is_owner;
-
-               uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
-               if (rsv->target.type == UWB_RSV_TARGET_DEV) {
-                       devaddr = rsv->target.dev->dev_addr;
-                       is_owner = &rc->uwb_dev == rsv->owner;
-               } else {
-                       devaddr = rsv->target.devaddr;
-                       is_owner = true;
-               }
-               uwb_dev_addr_print(target, sizeof(target), &devaddr);
-
-               seq_printf(s, "%c %s -> %s: %s\n",
-                          is_owner ? 'O' : 'T',
-                          owner, target, uwb_rsv_state_str(rsv->state));
-               seq_printf(s, "  stream: %d  type: %s\n",
-                          rsv->stream, uwb_rsv_type_str(rsv->type));
-               seq_printf(s, "  %*pb\n", UWB_NUM_MAS, rsv->mas.bm);
-       }
-
-       mutex_unlock(&rc->rsvs_mutex);
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(reservations);
-
-static int drp_avail_show(struct seq_file *s, void *p)
-{
-       struct uwb_rc *rc = s->private;
-
-       seq_printf(s, "global:  %*pb\n", UWB_NUM_MAS, rc->drp_avail.global);
-       seq_printf(s, "local:   %*pb\n", UWB_NUM_MAS, rc->drp_avail.local);
-       seq_printf(s, "pending: %*pb\n", UWB_NUM_MAS, rc->drp_avail.pending);
-
-       return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(drp_avail);
-
-static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel)
-{
-       struct device *dev = &pal->rc->uwb_dev.dev;
-
-       if (channel > 0)
-               dev_info(dev, "debug: channel %d started\n", channel);
-       else
-               dev_info(dev, "debug: channel stopped\n");
-}
-
-static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv)
-{
-       struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal);
-
-       if (dbg->accept) {
-               spin_lock(&dbg->list_lock);
-               list_add_tail(&rsv->pal_node, &dbg->rsvs);
-               spin_unlock(&dbg->list_lock);
-               uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, dbg);
-       }
-}
-
-/**
- * uwb_dbg_add_rc - add a debug interface for a radio controller
- * @rc: the radio controller
- */
-void uwb_dbg_add_rc(struct uwb_rc *rc)
-{
-       rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL);
-       if (rc->dbg == NULL)
-               return;
-
-       INIT_LIST_HEAD(&rc->dbg->rsvs);
-       spin_lock_init(&(rc->dbg)->list_lock);
-
-       uwb_pal_init(&rc->dbg->pal);
-       rc->dbg->pal.rc = rc;
-       rc->dbg->pal.channel_changed = uwb_dbg_channel_changed;
-       rc->dbg->pal.new_rsv = uwb_dbg_new_rsv;
-       uwb_pal_register(&rc->dbg->pal);
-
-       if (root_dir) {
-               rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev),
-                                                    root_dir);
-               rc->dbg->command_f = debugfs_create_file("command", 0200,
-                                                        rc->dbg->root_d, rc,
-                                                        &command_fops);
-               rc->dbg->reservations_f = debugfs_create_file("reservations", 0444,
-                                                             rc->dbg->root_d, rc,
-                                                             &reservations_fops);
-               rc->dbg->accept_f = debugfs_create_bool("accept", 0644,
-                                                       rc->dbg->root_d,
-                                                       &rc->dbg->accept);
-               rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444,
-                                                          rc->dbg->root_d, rc,
-                                                          &drp_avail_fops);
-       }
-}
-
-/**
- * uwb_dbg_del_rc - remove a radio controller's debug interface
- * @rc: the radio controller
- */
-void uwb_dbg_del_rc(struct uwb_rc *rc)
-{
-       struct uwb_rsv *rsv, *t;
-
-       if (rc->dbg == NULL)
-               return;
-
-       list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) {
-               uwb_rsv_terminate(rsv);
-       }
-
-       uwb_pal_unregister(&rc->dbg->pal);
-
-       if (root_dir) {
-               debugfs_remove(rc->dbg->drp_avail_f);
-               debugfs_remove(rc->dbg->accept_f);
-               debugfs_remove(rc->dbg->reservations_f);
-               debugfs_remove(rc->dbg->command_f);
-               debugfs_remove(rc->dbg->root_d);
-       }
-}
-
-/**
- * uwb_dbg_exit - initialize the debug interface sub-module
- */
-void uwb_dbg_init(void)
-{
-       root_dir = debugfs_create_dir("uwb", NULL);
-}
-
-/**
- * uwb_dbg_exit - clean-up the debug interface sub-module
- */
-void uwb_dbg_exit(void)
-{
-       debugfs_remove(root_dir);
-}
-
-/**
- * uwb_dbg_create_pal_dir - create a debugfs directory for a PAL
- * @pal: The PAL.
- */
-struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal)
-{
-       struct uwb_rc *rc = pal->rc;
-
-       if (root_dir && rc->dbg && rc->dbg->root_d && pal->name)
-               return debugfs_create_dir(pal->name, rc->dbg->root_d);
-       return NULL;
-}
diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h
deleted file mode 100644 (file)
index 00de0a5..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Ultra Wide Band
- * UWB internal API
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This contains most of the internal API for UWB. This is stuff used
- * across the stack that of course, is of no interest to the rest.
- *
- * Some parts might end up going public (like uwb_rc_*())...
- */
-
-#ifndef __UWB_INTERNAL_H__
-#define __UWB_INTERNAL_H__
-
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/uwb.h>
-#include <linux/mutex.h>
-
-struct uwb_beca_e;
-
-/* General device API */
-extern void uwb_dev_init(struct uwb_dev *uwb_dev);
-extern int __uwb_dev_offair(struct uwb_dev *, struct uwb_rc *);
-extern int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev,
-                      struct uwb_rc *parent_rc);
-extern void uwb_dev_rm(struct uwb_dev *uwb_dev);
-extern void uwbd_dev_onair(struct uwb_rc *, struct uwb_beca_e *);
-extern void uwbd_dev_offair(struct uwb_beca_e *);
-void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event);
-
-/* General UWB Radio Controller Internal API */
-extern struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *);
-static inline struct uwb_rc *__uwb_rc_get(struct uwb_rc *rc)
-{
-       uwb_dev_get(&rc->uwb_dev);
-       return rc;
-}
-
-static inline void __uwb_rc_put(struct uwb_rc *rc)
-{
-       if (rc)
-               uwb_dev_put(&rc->uwb_dev);
-}
-
-extern int uwb_rc_reset(struct uwb_rc *rc);
-extern int uwb_rc_beacon(struct uwb_rc *rc,
-                        int channel, unsigned bpst_offset);
-extern int uwb_rc_scan(struct uwb_rc *rc,
-                      unsigned channel, enum uwb_scan_type type,
-                      unsigned bpst_offset);
-extern int uwb_rc_send_all_drp_ie(struct uwb_rc *rc);
-
-void uwb_rc_ie_init(struct uwb_rc *);
-int uwb_rc_ie_setup(struct uwb_rc *);
-void uwb_rc_ie_release(struct uwb_rc *);
-int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len,
-                   char *buf, size_t size);
-int uwb_rc_set_ie(struct uwb_rc *, struct uwb_rc_cmd_set_ie *);
-
-
-extern const char *uwb_rc_strerror(unsigned code);
-
-/*
- * Time to wait for a response to an RC command.
- *
- * Some commands can take a long time to response. e.g., START_BEACON
- * may scan for several superframes before joining an existing beacon
- * group and this can take around 600 ms.
- */
-#define UWB_RC_CMD_TIMEOUT_MS 1000 /* ms */
-
-/*
- * Notification/Event Handlers
- */
-
-struct uwb_rc_neh;
-
-extern int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
-                           struct uwb_rccb *cmd, size_t cmd_size,
-                           u8 expected_type, u16 expected_event,
-                           uwb_rc_cmd_cb_f cb, void *arg);
-
-
-void uwb_rc_neh_create(struct uwb_rc *rc);
-void uwb_rc_neh_destroy(struct uwb_rc *rc);
-
-struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd,
-                                 u8 expected_type, u16 expected_event,
-                                 uwb_rc_cmd_cb_f cb, void *arg);
-void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
-void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh);
-void uwb_rc_neh_put(struct uwb_rc_neh *neh);
-
-/* Event size tables */
-extern int uwb_est_create(void);
-extern void uwb_est_destroy(void);
-
-/*
- * UWB conflicting alien reservations
- */
-struct uwb_cnflt_alien {
-       struct uwb_rc *rc;
-       struct list_head rc_node;
-       struct uwb_mas_bm mas;
-       struct timer_list timer;
-       struct work_struct cnflt_update_work;
-};
-
-enum uwb_uwb_rsv_alloc_result {
-       UWB_RSV_ALLOC_FOUND = 0,
-       UWB_RSV_ALLOC_NOT_FOUND,
-};
-
-enum uwb_rsv_mas_status {
-       UWB_RSV_MAS_NOT_AVAIL = 1,
-       UWB_RSV_MAS_SAFE,
-       UWB_RSV_MAS_UNSAFE,
-};
-
-struct uwb_rsv_col_set_info {
-       unsigned char start_col;
-       unsigned char interval;
-       unsigned char safe_mas_per_col;
-       unsigned char unsafe_mas_per_col;
-};
-
-struct uwb_rsv_col_info {
-       unsigned char max_avail_safe;
-       unsigned char max_avail_unsafe;
-       unsigned char highest_mas[UWB_MAS_PER_ZONE];
-       struct uwb_rsv_col_set_info csi;
-};
-
-struct uwb_rsv_row_info {
-       unsigned char avail[UWB_MAS_PER_ZONE];
-       unsigned char free_rows;
-       unsigned char used_rows;
-};
-
-/*
- * UWB find allocation
- */
-struct uwb_rsv_alloc_info {
-       unsigned char bm[UWB_MAS_PER_ZONE * UWB_NUM_ZONES];
-       struct uwb_rsv_col_info ci[UWB_NUM_ZONES];
-       struct uwb_rsv_row_info ri;
-       struct uwb_mas_bm *not_available;
-       struct uwb_mas_bm *result;
-       int min_mas;
-       int max_mas;
-       int max_interval;
-       int total_allocated_mases;
-       int safe_allocated_mases;
-       int unsafe_allocated_mases;
-       int interval;
-};
-
-int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv,
-                                struct uwb_mas_bm *available,
-                                struct uwb_mas_bm *result);
-void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc);
-/*
- * UWB Events & management daemon
- */
-
-/**
- * enum uwb_event_type - types of UWB management daemon events
- *
- * The UWB management daemon (uwbd) can receive two types of events:
- *   UWB_EVT_TYPE_NOTIF - notification from the radio controller.
- *   UWB_EVT_TYPE_MSG   - a simple message.
- */
-enum uwb_event_type {
-       UWB_EVT_TYPE_NOTIF,
-       UWB_EVT_TYPE_MSG,
-};
-
-/**
- * struct uwb_event_notif - an event for a radio controller notification
- * @size: Size of the buffer (ie: Guaranteed to contain at least
- *        a full 'struct uwb_rceb')
- * @rceb: Pointer to a kmalloced() event payload
- */
-struct uwb_event_notif {
-       size_t size;
-       struct uwb_rceb *rceb;
-};
-
-/**
- * enum uwb_event_message - an event for a message for asynchronous processing
- *
- * UWB_EVT_MSG_RESET - reset the radio controller and all PAL hardware.
- */
-enum uwb_event_message {
-       UWB_EVT_MSG_RESET,
-};
-
-/**
- * UWB Event
- * @rc:         Radio controller that emitted the event (referenced)
- * @ts_jiffies: Timestamp, when was it received
- * @type:       This event's type.
- */
-struct uwb_event {
-       struct list_head list_node;
-       struct uwb_rc *rc;
-       unsigned long ts_jiffies;
-       enum uwb_event_type type;
-       union {
-               struct uwb_event_notif notif;
-               enum uwb_event_message message;
-       };
-};
-
-extern void uwbd_start(struct uwb_rc *rc);
-extern void uwbd_stop(struct uwb_rc *rc);
-extern struct uwb_event *uwb_event_alloc(size_t, gfp_t gfp_mask);
-extern void uwbd_event_queue(struct uwb_event *);
-void uwbd_flush(struct uwb_rc *rc);
-
-/* UWB event handlers */
-extern int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *);
-extern int uwbd_evt_handle_rc_beacon(struct uwb_event *);
-extern int uwbd_evt_handle_rc_beacon_size(struct uwb_event *);
-extern int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *);
-extern int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *);
-extern int uwbd_evt_handle_rc_drp(struct uwb_event *);
-extern int uwbd_evt_handle_rc_drp_avail(struct uwb_event *);
-
-int uwbd_msg_handle_reset(struct uwb_event *evt);
-
-
-/*
- * Address management
- */
-int uwb_rc_dev_addr_assign(struct uwb_rc *rc);
-int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt);
-
-/*
- * UWB Beacon Cache
- *
- * Each beacon we received is kept in a cache--when we receive that
- * beacon consistently, that means there is a new device that we have
- * to add to the system.
- */
-
-extern unsigned long beacon_timeout_ms;
-
-/**
- * Beacon cache entry
- *
- * @jiffies_refresh: last time a beacon was  received that refreshed
- *                   this cache entry.
- * @uwb_dev: device connected to this beacon. This pointer is not
- *           safe, you need to get it with uwb_dev_try_get()
- *
- * @hits: how many time we have seen this beacon since last time we
- *        cleared it
- */
-struct uwb_beca_e {
-       struct mutex mutex;
-       struct kref refcnt;
-       struct list_head node;
-       struct uwb_mac_addr *mac_addr;
-       struct uwb_dev_addr dev_addr;
-       u8 hits;
-       unsigned long ts_jiffies;
-       struct uwb_dev *uwb_dev;
-       struct uwb_rc_evt_beacon *be;
-       struct stats lqe_stats, rssi_stats;     /* radio statistics */
-};
-struct uwb_beacon_frame;
-extern ssize_t uwb_bce_print_IEs(struct uwb_dev *, struct uwb_beca_e *,
-                                char *, size_t);
-
-extern void uwb_bce_kfree(struct kref *_bce);
-static inline void uwb_bce_get(struct uwb_beca_e *bce)
-{
-       kref_get(&bce->refcnt);
-}
-static inline void uwb_bce_put(struct uwb_beca_e *bce)
-{
-       kref_put(&bce->refcnt, uwb_bce_kfree);
-}
-extern void uwb_beca_purge(struct uwb_rc *rc);
-extern void uwb_beca_release(struct uwb_rc *rc);
-
-struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
-                                      const struct uwb_dev_addr *devaddr);
-struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc,
-                                      const struct uwb_mac_addr *macaddr);
-
-int uwb_radio_setup(struct uwb_rc *rc);
-void uwb_radio_reset_state(struct uwb_rc *rc);
-void uwb_radio_shutdown(struct uwb_rc *rc);
-int uwb_radio_force_channel(struct uwb_rc *rc, int channel);
-
-/* -- UWB Sysfs representation */
-extern struct class uwb_rc_class;
-extern struct bus_type uwb_bus_type;
-extern struct device_attribute dev_attr_mac_address;
-extern struct device_attribute dev_attr_beacon;
-extern struct device_attribute dev_attr_scan;
-
-/* -- DRP Bandwidth allocator: bandwidth allocations, reservations, DRP */
-void uwb_rsv_init(struct uwb_rc *rc);
-int uwb_rsv_setup(struct uwb_rc *rc);
-void uwb_rsv_cleanup(struct uwb_rc *rc);
-void uwb_rsv_remove_all(struct uwb_rc *rc);
-void uwb_rsv_get(struct uwb_rsv *rsv);
-void uwb_rsv_put(struct uwb_rsv *rsv);
-bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv);
-void uwb_rsv_dump(char *text, struct uwb_rsv *rsv);
-int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available);
-void uwb_rsv_backoff_win_timer(struct timer_list *t);
-void uwb_rsv_backoff_win_increment(struct uwb_rc *rc);
-int uwb_rsv_status(struct uwb_rsv *rsv);
-int uwb_rsv_companion_status(struct uwb_rsv *rsv);
-
-void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state);
-void uwb_rsv_remove(struct uwb_rsv *rsv);
-struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src,
-                            struct uwb_ie_drp *drp_ie);
-void uwb_rsv_sched_update(struct uwb_rc *rc);
-void uwb_rsv_queue_update(struct uwb_rc *rc);
-
-int uwb_drp_ie_update(struct uwb_rsv *rsv);
-void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie);
-
-void uwb_drp_avail_init(struct uwb_rc *rc);
-void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail);
-int  uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas);
-void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas);
-void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas);
-void uwb_drp_avail_ie_update(struct uwb_rc *rc);
-
-/* -- PAL support */
-void uwb_rc_pal_init(struct uwb_rc *rc);
-
-/* -- Misc */
-
-extern ssize_t uwb_mac_frame_hdr_print(char *, size_t,
-                                      const struct uwb_mac_frame_hdr *);
-
-/* -- Debug interface */
-void uwb_dbg_init(void);
-void uwb_dbg_exit(void);
-void uwb_dbg_add_rc(struct uwb_rc *rc);
-void uwb_dbg_del_rc(struct uwb_rc *rc);
-struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal);
-
-static inline void uwb_dev_lock(struct uwb_dev *uwb_dev)
-{
-       device_lock(&uwb_dev->dev);
-}
-
-static inline void uwb_dev_unlock(struct uwb_dev *uwb_dev)
-{
-       device_unlock(&uwb_dev->dev);
-}
-
-#endif /* #ifndef __UWB_INTERNAL_H__ */
diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c
deleted file mode 100644 (file)
index dc5c743..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Ultra Wide Band
- * Neighborhood Management Daemon
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This daemon takes care of maintaing information that describes the
- * UWB neighborhood that the radios in this machine can see. It also
- * keeps a tab of which devices are visible, makes sure each HC sits
- * on a different channel to avoid interfering, etc.
- *
- * Different drivers (radio controller, device, any API in general)
- * communicate with this daemon through an event queue. Daemon wakes
- * up, takes a list of events and handles them one by one; handling
- * function is extracted from a table based on the event's type and
- * subtype. Events are freed only if the handling function says so.
- *
- *   . Lock protecting the event list has to be an spinlock and locked
- *     with IRQSAVE because it might be called from an interrupt
- *     context (ie: when events arrive and the notification drops
- *     down from the ISR).
- *
- *   . UWB radio controller drivers queue events to the daemon using
- *     uwbd_event_queue(). They just get the event, chew it to make it
- *     look like UWBD likes it and pass it in a buffer allocated with
- *     uwb_event_alloc().
- *
- * EVENTS
- *
- * Events have a type, a subtype, a length, some other stuff and the
- * data blob, which depends on the event. The header is 'struct
- * uwb_event'; for payloads, see 'struct uwbd_evt_*'.
- *
- * EVENT HANDLER TABLES
- *
- * To find a handling function for an event, the type is used to index
- * a subtype-table in the type-table. The subtype-table is indexed
- * with the subtype to get the function that handles the event. Start
- * with the main type-table 'uwbd_evt_type_handler'.
- *
- * DEVICES
- *
- * Devices are created when a bunch of beacons have been received and
- * it is stablished that the device has stable radio presence. CREATED
- * only, not configured. Devices are ONLY configured when an
- * Application-Specific IE Probe is receieved, in which the device
- * declares which Protocol ID it groks. Then the device is CONFIGURED
- * (and the driver->probe() stuff of the device model is invoked).
- *
- * Devices are considered disconnected when a certain number of
- * beacons are not received in an amount of time.
- *
- * Handler functions are called normally uwbd_evt_handle_*().
- */
-#include <linux/kthread.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/freezer.h>
-
-#include "uwb-internal.h"
-
-/*
- * UWBD Event handler function signature
- *
- * Return !0 if the event needs not to be freed (ie the handler
- * takes/took care of it). 0 means the daemon code will free the
- * event.
- *
- * @evt->rc is already referenced and guaranteed to exist. See
- * uwb_evt_handle().
- */
-typedef int (*uwbd_evt_handler_f)(struct uwb_event *);
-
-/**
- * Properties of a UWBD event
- *
- * @handler:    the function that will handle this event
- * @name:       text name of event
- */
-struct uwbd_event {
-       uwbd_evt_handler_f handler;
-       const char *name;
-};
-
-/* Table of handlers for and properties of the UWBD Radio Control Events */
-static struct uwbd_event uwbd_urc_events[] = {
-       [UWB_RC_EVT_IE_RCV] = {
-               .handler = uwbd_evt_handle_rc_ie_rcv,
-               .name = "IE_RECEIVED"
-       },
-       [UWB_RC_EVT_BEACON] = {
-               .handler = uwbd_evt_handle_rc_beacon,
-               .name = "BEACON_RECEIVED"
-       },
-       [UWB_RC_EVT_BEACON_SIZE] = {
-               .handler = uwbd_evt_handle_rc_beacon_size,
-               .name = "BEACON_SIZE_CHANGE"
-       },
-       [UWB_RC_EVT_BPOIE_CHANGE] = {
-               .handler = uwbd_evt_handle_rc_bpoie_change,
-               .name = "BPOIE_CHANGE"
-       },
-       [UWB_RC_EVT_BP_SLOT_CHANGE] = {
-               .handler = uwbd_evt_handle_rc_bp_slot_change,
-               .name = "BP_SLOT_CHANGE"
-       },
-       [UWB_RC_EVT_DRP_AVAIL] = {
-               .handler = uwbd_evt_handle_rc_drp_avail,
-               .name = "DRP_AVAILABILITY_CHANGE"
-       },
-       [UWB_RC_EVT_DRP] = {
-               .handler = uwbd_evt_handle_rc_drp,
-               .name = "DRP"
-       },
-       [UWB_RC_EVT_DEV_ADDR_CONFLICT] = {
-               .handler = uwbd_evt_handle_rc_dev_addr_conflict,
-               .name = "DEV_ADDR_CONFLICT",
-       },
-};
-
-
-
-struct uwbd_evt_type_handler {
-       const char *name;
-       struct uwbd_event *uwbd_events;
-       size_t size;
-};
-
-/* Table of handlers for each UWBD Event type. */
-static struct uwbd_evt_type_handler uwbd_urc_evt_type_handlers[] = {
-       [UWB_RC_CET_GENERAL] = {
-               .name        = "URC",
-               .uwbd_events = uwbd_urc_events,
-               .size        = ARRAY_SIZE(uwbd_urc_events),
-       },
-};
-
-static const struct uwbd_event uwbd_message_handlers[] = {
-       [UWB_EVT_MSG_RESET] = {
-               .handler = uwbd_msg_handle_reset,
-               .name = "reset",
-       },
-};
-
-/*
- * Handle an URC event passed to the UWB Daemon
- *
- * @evt: the event to handle
- * @returns: 0 if the event can be kfreed, !0 on the contrary
- *           (somebody else took ownership) [coincidentally, returning
- *           a <0 errno code will free it :)].
- *
- * Looks up the two indirection tables (one for the type, one for the
- * subtype) to decide which function handles it and then calls the
- * handler.
- *
- * The event structure passed to the event handler has the radio
- * controller in @evt->rc referenced. The reference will be dropped
- * once the handler returns, so if it needs it for longer (async),
- * it'll need to take another one.
- */
-static
-int uwbd_event_handle_urc(struct uwb_event *evt)
-{
-       int result = -EINVAL;
-       struct uwbd_evt_type_handler *type_table;
-       uwbd_evt_handler_f handler;
-       u8 type, context;
-       u16 event;
-
-       type = evt->notif.rceb->bEventType;
-       event = le16_to_cpu(evt->notif.rceb->wEvent);
-       context = evt->notif.rceb->bEventContext;
-
-       if (type >= ARRAY_SIZE(uwbd_urc_evt_type_handlers))
-               goto out;
-       type_table = &uwbd_urc_evt_type_handlers[type];
-       if (type_table->uwbd_events == NULL)
-               goto out;
-       if (event >= type_table->size)
-               goto out;
-       handler = type_table->uwbd_events[event].handler;
-       if (handler == NULL)
-               goto out;
-
-       result = (*handler)(evt);
-out:
-       if (result < 0)
-               dev_err(&evt->rc->uwb_dev.dev,
-                       "UWBD: event 0x%02x/%04x/%02x, handling failed: %d\n",
-                       type, event, context, result);
-       return result;
-}
-
-static void uwbd_event_handle_message(struct uwb_event *evt)
-{
-       struct uwb_rc *rc;
-       int result;
-
-       rc = evt->rc;
-
-       if (evt->message < 0 || evt->message >= ARRAY_SIZE(uwbd_message_handlers)) {
-               dev_err(&rc->uwb_dev.dev, "UWBD: invalid message type %d\n", evt->message);
-               return;
-       }
-
-       result = uwbd_message_handlers[evt->message].handler(evt);
-       if (result < 0)
-               dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n",
-                       uwbd_message_handlers[evt->message].name, result);
-}
-
-static void uwbd_event_handle(struct uwb_event *evt)
-{
-       struct uwb_rc *rc;
-       int should_keep;
-
-       rc = evt->rc;
-
-       if (rc->ready) {
-               switch (evt->type) {
-               case UWB_EVT_TYPE_NOTIF:
-                       should_keep = uwbd_event_handle_urc(evt);
-                       if (should_keep <= 0)
-                               kfree(evt->notif.rceb);
-                       break;
-               case UWB_EVT_TYPE_MSG:
-                       uwbd_event_handle_message(evt);
-                       break;
-               default:
-                       dev_err(&rc->uwb_dev.dev, "UWBD: invalid event type %d\n", evt->type);
-                       break;
-               }
-       }
-
-       __uwb_rc_put(rc);       /* for the __uwb_rc_get() in uwb_rc_notif_cb() */
-}
-
-/**
- * UWB Daemon
- *
- * Listens to all UWB notifications and takes care to track the state
- * of the UWB neighbourhood for the kernel. When we do a run, we
- * spinlock, move the list to a private copy and release the
- * lock. Hold it as little as possible. Not a conflict: it is
- * guaranteed we own the events in the private list.
- *
- * FIXME: should change so we don't have a 1HZ timer all the time, but
- *        only if there are devices.
- */
-static int uwbd(void *param)
-{
-       struct uwb_rc *rc = param;
-       unsigned long flags;
-       struct uwb_event *evt;
-       int should_stop = 0;
-
-       while (1) {
-               wait_event_interruptible_timeout(
-                       rc->uwbd.wq,
-                       !list_empty(&rc->uwbd.event_list)
-                         || (should_stop = kthread_should_stop()),
-                       HZ);
-               if (should_stop)
-                       break;
-
-               spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
-               if (!list_empty(&rc->uwbd.event_list)) {
-                       evt = list_first_entry(&rc->uwbd.event_list, struct uwb_event, list_node);
-                       list_del(&evt->list_node);
-               } else
-                       evt = NULL;
-               spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
-
-               if (evt) {
-                       uwbd_event_handle(evt);
-                       kfree(evt);
-               }
-
-               uwb_beca_purge(rc);     /* Purge devices that left */
-       }
-       return 0;
-}
-
-
-/** Start the UWB daemon */
-void uwbd_start(struct uwb_rc *rc)
-{
-       struct task_struct *task = kthread_run(uwbd, rc, "uwbd");
-       if (IS_ERR(task)) {
-               rc->uwbd.task = NULL;
-               printk(KERN_ERR "UWB: Cannot start management daemon; "
-                      "UWB won't work\n");
-       } else {
-               rc->uwbd.task = task;
-               rc->uwbd.pid = rc->uwbd.task->pid;
-       }
-}
-
-/* Stop the UWB daemon and free any unprocessed events */
-void uwbd_stop(struct uwb_rc *rc)
-{
-       if (rc->uwbd.task)
-               kthread_stop(rc->uwbd.task);
-       uwbd_flush(rc);
-}
-
-/*
- * Queue an event for the management daemon
- *
- * When some lower layer receives an event, it uses this function to
- * push it forward to the UWB daemon.
- *
- * Once you pass the event, you don't own it any more, but the daemon
- * does. It will uwb_event_free() it when done, so make sure you
- * uwb_event_alloc()ed it or bad things will happen.
- *
- * If the daemon is not running, we just free the event.
- */
-void uwbd_event_queue(struct uwb_event *evt)
-{
-       struct uwb_rc *rc = evt->rc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&rc->uwbd.event_list_lock, flags);
-       if (rc->uwbd.pid != 0) {
-               list_add(&evt->list_node, &rc->uwbd.event_list);
-               wake_up_all(&rc->uwbd.wq);
-       } else {
-               __uwb_rc_put(evt->rc);
-               if (evt->type == UWB_EVT_TYPE_NOTIF)
-                       kfree(evt->notif.rceb);
-               kfree(evt);
-       }
-       spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags);
-       return;
-}
-
-void uwbd_flush(struct uwb_rc *rc)
-{
-       struct uwb_event *evt, *nxt;
-
-       spin_lock_irq(&rc->uwbd.event_list_lock);
-       list_for_each_entry_safe(evt, nxt, &rc->uwbd.event_list, list_node) {
-               if (evt->rc == rc) {
-                       __uwb_rc_put(rc);
-                       list_del(&evt->list_node);
-                       if (evt->type == UWB_EVT_TYPE_NOTIF)
-                               kfree(evt->notif.rceb);
-                       kfree(evt);
-               }
-       }
-       spin_unlock_irq(&rc->uwbd.event_list_lock);
-}
diff --git a/drivers/uwb/whc-rc.c b/drivers/uwb/whc-rc.c
deleted file mode 100644 (file)
index 22397f7..0000000
+++ /dev/null
@@ -1,467 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Wireless Host Controller: Radio Control Interface (WHCI v0.95[2.3])
- * Radio Control command/event transport to the UWB stack
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * Initialize and hook up the Radio Control interface.
- *
- * For each device probed, creates an 'struct whcrc' which contains
- * just the representation of the UWB Radio Controller, and the logic
- * for reading notifications and passing them to the UWB Core.
- *
- * So we initialize all of those, register the UWB Radio Controller
- * and setup the notification/event handle to pipe the notifications
- * to the UWB management Daemon.
- *
- * Once uwb_rc_add() is called, the UWB stack takes control, resets
- * the radio and readies the device to take commands the UWB
- * API/user-space.
- *
- * Note this driver is just a transport driver; the commands are
- * formed at the UWB stack and given to this driver who will deliver
- * them to the hw and transfer the replies/notifications back to the
- * UWB stack through the UWB daemon (UWBD).
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/dma-mapping.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/uwb.h>
-#include <linux/uwb/whci.h>
-#include <linux/uwb/umc.h>
-
-#include "uwb-internal.h"
-
-/**
- * Descriptor for an instance of the UWB Radio Control Driver that
- * attaches to the URC interface of the WHCI PCI card.
- *
- * Unless there is a lock specific to the 'data members', all access
- * is protected by uwb_rc->mutex.
- */
-struct whcrc {
-       struct umc_dev *umc_dev;
-       struct uwb_rc *uwb_rc;          /* UWB host controller */
-
-       unsigned long area;
-       void __iomem *rc_base;
-       size_t rc_len;
-       spinlock_t irq_lock;
-
-       void *evt_buf, *cmd_buf;
-       dma_addr_t evt_dma_buf, cmd_dma_buf;
-       wait_queue_head_t cmd_wq;
-       struct work_struct event_work;
-};
-
-/**
- * Execute an UWB RC command on WHCI/RC
- *
- * @rc:       Instance of a Radio Controller that is a whcrc
- * @cmd:      Buffer containing the RCCB and payload to execute
- * @cmd_size: Size of the command buffer.
- *
- * We copy the command into whcrc->cmd_buf (as it is pretty and
- * aligned`and physically contiguous) and then press the right keys in
- * the controller's URCCMD register to get it to read it. We might
- * have to wait for the cmd_sem to be open to us.
- *
- * NOTE: rc's mutex has to be locked
- */
-static int whcrc_cmd(struct uwb_rc *uwb_rc,
-             const struct uwb_rccb *cmd, size_t cmd_size)
-{
-       int result = 0;
-       struct whcrc *whcrc = uwb_rc->priv;
-       struct device *dev = &whcrc->umc_dev->dev;
-       u32 urccmd;
-
-       if (cmd_size >= 4096)
-               return -EINVAL;
-
-       /*
-        * If the URC is halted, then the hardware has reset itself.
-        * Attempt to recover by restarting the device and then return
-        * an error as it's likely that the current command isn't
-        * valid for a newly started RC.
-        */
-       if (le_readl(whcrc->rc_base + URCSTS) & URCSTS_HALTED) {
-               dev_err(dev, "requesting reset of halted radio controller\n");
-               uwb_rc_reset_all(uwb_rc);
-               return -EIO;
-       }
-
-       result = wait_event_timeout(whcrc->cmd_wq,
-               !(le_readl(whcrc->rc_base + URCCMD) & URCCMD_ACTIVE), HZ/2);
-       if (result == 0) {
-               dev_err(dev, "device is not ready to execute commands\n");
-               return -ETIMEDOUT;
-       }
-
-       memmove(whcrc->cmd_buf, cmd, cmd_size);
-       le_writeq(whcrc->cmd_dma_buf, whcrc->rc_base + URCCMDADDR);
-
-       spin_lock(&whcrc->irq_lock);
-       urccmd = le_readl(whcrc->rc_base + URCCMD);
-       urccmd &= ~(URCCMD_EARV | URCCMD_SIZE_MASK);
-       le_writel(urccmd | URCCMD_ACTIVE | URCCMD_IWR | cmd_size,
-                 whcrc->rc_base + URCCMD);
-       spin_unlock(&whcrc->irq_lock);
-
-       return 0;
-}
-
-static int whcrc_reset(struct uwb_rc *rc)
-{
-       struct whcrc *whcrc = rc->priv;
-
-       return umc_controller_reset(whcrc->umc_dev);
-}
-
-/**
- * Reset event reception mechanism and tell hw we are ready to get more
- *
- * We have read all the events in the event buffer, so we are ready to
- * reset it to the beginning.
- *
- * This is only called during initialization or after an event buffer
- * has been retired.  This means we can be sure that event processing
- * is disabled and it's safe to update the URCEVTADDR register.
- *
- * There's no need to wait for the event processing to start as the
- * URC will not clear URCCMD_ACTIVE until (internal) event buffer
- * space is available.
- */
-static
-void whcrc_enable_events(struct whcrc *whcrc)
-{
-       u32 urccmd;
-
-       le_writeq(whcrc->evt_dma_buf, whcrc->rc_base + URCEVTADDR);
-
-       spin_lock(&whcrc->irq_lock);
-       urccmd = le_readl(whcrc->rc_base + URCCMD) & ~URCCMD_ACTIVE;
-       le_writel(urccmd | URCCMD_EARV, whcrc->rc_base + URCCMD);
-       spin_unlock(&whcrc->irq_lock);
-}
-
-static void whcrc_event_work(struct work_struct *work)
-{
-       struct whcrc *whcrc = container_of(work, struct whcrc, event_work);
-       size_t size;
-       u64 urcevtaddr;
-
-       urcevtaddr = le_readq(whcrc->rc_base + URCEVTADDR);
-       size = urcevtaddr & URCEVTADDR_OFFSET_MASK;
-
-       uwb_rc_neh_grok(whcrc->uwb_rc, whcrc->evt_buf, size);
-       whcrc_enable_events(whcrc);
-}
-
-/**
- * Catch interrupts?
- *
- * We ack inmediately (and expect the hw to do the right thing and
- * raise another IRQ if things have changed :)
- */
-static
-irqreturn_t whcrc_irq_cb(int irq, void *_whcrc)
-{
-       struct whcrc *whcrc = _whcrc;
-       struct device *dev = &whcrc->umc_dev->dev;
-       u32 urcsts;
-
-       urcsts = le_readl(whcrc->rc_base + URCSTS);
-       if (!(urcsts & URCSTS_INT_MASK))
-               return IRQ_NONE;
-       le_writel(urcsts & URCSTS_INT_MASK, whcrc->rc_base + URCSTS);
-
-       if (urcsts & URCSTS_HSE) {
-               dev_err(dev, "host system error -- hardware halted\n");
-               /* FIXME: do something sensible here */
-               goto out;
-       }
-       if (urcsts & URCSTS_ER)
-               schedule_work(&whcrc->event_work);
-       if (urcsts & URCSTS_RCI)
-               wake_up_all(&whcrc->cmd_wq);
-out:
-       return IRQ_HANDLED;
-}
-
-
-/**
- * Initialize a UMC RC interface: map regions, get (shared) IRQ
- */
-static
-int whcrc_setup_rc_umc(struct whcrc *whcrc)
-{
-       int result = 0;
-       struct device *dev = &whcrc->umc_dev->dev;
-       struct umc_dev *umc_dev = whcrc->umc_dev;
-
-       whcrc->area = umc_dev->resource.start;
-       whcrc->rc_len = resource_size(&umc_dev->resource);
-       result = -EBUSY;
-       if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME) == NULL) {
-               dev_err(dev, "can't request URC region (%zu bytes @ 0x%lx): %d\n",
-                       whcrc->rc_len, whcrc->area, result);
-               goto error_request_region;
-       }
-
-       whcrc->rc_base = ioremap_nocache(whcrc->area, whcrc->rc_len);
-       if (whcrc->rc_base == NULL) {
-               dev_err(dev, "can't ioremap registers (%zu bytes @ 0x%lx): %d\n",
-                       whcrc->rc_len, whcrc->area, result);
-               goto error_ioremap_nocache;
-       }
-
-       result = request_irq(umc_dev->irq, whcrc_irq_cb, IRQF_SHARED,
-                            KBUILD_MODNAME, whcrc);
-       if (result < 0) {
-               dev_err(dev, "can't allocate IRQ %d: %d\n",
-                       umc_dev->irq, result);
-               goto error_request_irq;
-       }
-
-       result = -ENOMEM;
-       whcrc->cmd_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
-                                           &whcrc->cmd_dma_buf, GFP_KERNEL);
-       if (whcrc->cmd_buf == NULL) {
-               dev_err(dev, "Can't allocate cmd transfer buffer\n");
-               goto error_cmd_buffer;
-       }
-
-       whcrc->evt_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
-                                           &whcrc->evt_dma_buf, GFP_KERNEL);
-       if (whcrc->evt_buf == NULL) {
-               dev_err(dev, "Can't allocate evt transfer buffer\n");
-               goto error_evt_buffer;
-       }
-       return 0;
-
-error_evt_buffer:
-       dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
-                         whcrc->cmd_dma_buf);
-error_cmd_buffer:
-       free_irq(umc_dev->irq, whcrc);
-error_request_irq:
-       iounmap(whcrc->rc_base);
-error_ioremap_nocache:
-       release_mem_region(whcrc->area, whcrc->rc_len);
-error_request_region:
-       return result;
-}
-
-
-/**
- * Release RC's UMC resources
- */
-static
-void whcrc_release_rc_umc(struct whcrc *whcrc)
-{
-       struct umc_dev *umc_dev = whcrc->umc_dev;
-
-       dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->evt_buf,
-                         whcrc->evt_dma_buf);
-       dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
-                         whcrc->cmd_dma_buf);
-       free_irq(umc_dev->irq, whcrc);
-       iounmap(whcrc->rc_base);
-       release_mem_region(whcrc->area, whcrc->rc_len);
-}
-
-
-/**
- * whcrc_start_rc - start a WHCI radio controller
- * @whcrc: the radio controller to start
- *
- * Reset the UMC device, start the radio controller, enable events and
- * finally enable interrupts.
- */
-static int whcrc_start_rc(struct uwb_rc *rc)
-{
-       struct whcrc *whcrc = rc->priv;
-       struct device *dev = &whcrc->umc_dev->dev;
-
-       /* Reset the thing */
-       le_writel(URCCMD_RESET, whcrc->rc_base + URCCMD);
-       if (whci_wait_for(dev, whcrc->rc_base + URCCMD, URCCMD_RESET, 0,
-                         5000, "hardware reset") < 0)
-               return -EBUSY;
-
-       /* Set the event buffer, start the controller (enable IRQs later) */
-       le_writel(0, whcrc->rc_base + URCINTR);
-       le_writel(URCCMD_RS, whcrc->rc_base + URCCMD);
-       if (whci_wait_for(dev, whcrc->rc_base + URCSTS, URCSTS_HALTED, 0,
-                         5000, "radio controller start") < 0)
-               return -ETIMEDOUT;
-       whcrc_enable_events(whcrc);
-       le_writel(URCINTR_EN_ALL, whcrc->rc_base + URCINTR);
-       return 0;
-}
-
-
-/**
- * whcrc_stop_rc - stop a WHCI radio controller
- * @whcrc: the radio controller to stop
- *
- * Disable interrupts and cancel any pending event processing work
- * before clearing the Run/Stop bit.
- */
-static
-void whcrc_stop_rc(struct uwb_rc *rc)
-{
-       struct whcrc *whcrc = rc->priv;
-       struct umc_dev *umc_dev = whcrc->umc_dev;
-
-       le_writel(0, whcrc->rc_base + URCINTR);
-       cancel_work_sync(&whcrc->event_work);
-
-       le_writel(0, whcrc->rc_base + URCCMD);
-       whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS,
-                     URCSTS_HALTED, URCSTS_HALTED, 100, "radio controller stop");
-}
-
-static void whcrc_init(struct whcrc *whcrc)
-{
-       spin_lock_init(&whcrc->irq_lock);
-       init_waitqueue_head(&whcrc->cmd_wq);
-       INIT_WORK(&whcrc->event_work, whcrc_event_work);
-}
-
-/**
- * Initialize the radio controller.
- *
- * NOTE: we setup whcrc->uwb_rc before calling uwb_rc_add(); in the
- *       IRQ handler we use that to determine if the hw is ready to
- *       handle events. Looks like a race condition, but it really is
- *       not.
- */
-static
-int whcrc_probe(struct umc_dev *umc_dev)
-{
-       int result;
-       struct uwb_rc *uwb_rc;
-       struct whcrc *whcrc;
-       struct device *dev = &umc_dev->dev;
-
-       result = -ENOMEM;
-       uwb_rc = uwb_rc_alloc();
-       if (uwb_rc == NULL) {
-               dev_err(dev, "unable to allocate RC instance\n");
-               goto error_rc_alloc;
-       }
-       whcrc = kzalloc(sizeof(*whcrc), GFP_KERNEL);
-       if (whcrc == NULL) {
-               dev_err(dev, "unable to allocate WHC-RC instance\n");
-               goto error_alloc;
-       }
-       whcrc_init(whcrc);
-       whcrc->umc_dev = umc_dev;
-
-       result = whcrc_setup_rc_umc(whcrc);
-       if (result < 0) {
-               dev_err(dev, "Can't setup RC UMC interface: %d\n", result);
-               goto error_setup_rc_umc;
-       }
-       whcrc->uwb_rc = uwb_rc;
-
-       uwb_rc->owner = THIS_MODULE;
-       uwb_rc->cmd   = whcrc_cmd;
-       uwb_rc->reset = whcrc_reset;
-       uwb_rc->start = whcrc_start_rc;
-       uwb_rc->stop  = whcrc_stop_rc;
-
-       result = uwb_rc_add(uwb_rc, dev, whcrc);
-       if (result < 0)
-               goto error_rc_add;
-       umc_set_drvdata(umc_dev, whcrc);
-       return 0;
-
-error_rc_add:
-       whcrc_release_rc_umc(whcrc);
-error_setup_rc_umc:
-       kfree(whcrc);
-error_alloc:
-       uwb_rc_put(uwb_rc);
-error_rc_alloc:
-       return result;
-}
-
-/**
- * Clean up the radio control resources
- *
- * When we up the command semaphore, everybody possibly held trying to
- * execute a command should be granted entry and then they'll see the
- * host is quiescing and up it (so it will chain to the next waiter).
- * This should not happen (in any case), as we can only remove when
- * there are no handles open...
- */
-static void whcrc_remove(struct umc_dev *umc_dev)
-{
-       struct whcrc *whcrc = umc_get_drvdata(umc_dev);
-       struct uwb_rc *uwb_rc = whcrc->uwb_rc;
-
-       umc_set_drvdata(umc_dev, NULL);
-       uwb_rc_rm(uwb_rc);
-       whcrc_release_rc_umc(whcrc);
-       kfree(whcrc);
-       uwb_rc_put(uwb_rc);
-}
-
-static int whcrc_pre_reset(struct umc_dev *umc)
-{
-       struct whcrc *whcrc = umc_get_drvdata(umc);
-       struct uwb_rc *uwb_rc = whcrc->uwb_rc;
-
-       uwb_rc_pre_reset(uwb_rc);
-       return 0;
-}
-
-static int whcrc_post_reset(struct umc_dev *umc)
-{
-       struct whcrc *whcrc = umc_get_drvdata(umc);
-       struct uwb_rc *uwb_rc = whcrc->uwb_rc;
-
-       return uwb_rc_post_reset(uwb_rc);
-}
-
-/* PCI device ID's that we handle [so it gets loaded] */
-static struct pci_device_id __used whcrc_id_table[] = {
-       { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
-       { /* empty last entry */ }
-};
-MODULE_DEVICE_TABLE(pci, whcrc_id_table);
-
-static struct umc_driver whcrc_driver = {
-       .name       = "whc-rc",
-       .cap_id     = UMC_CAP_ID_WHCI_RC,
-       .probe      = whcrc_probe,
-       .remove     = whcrc_remove,
-       .pre_reset  = whcrc_pre_reset,
-       .post_reset = whcrc_post_reset,
-};
-
-static int __init whcrc_driver_init(void)
-{
-       return umc_driver_register(&whcrc_driver);
-}
-module_init(whcrc_driver_init);
-
-static void __exit whcrc_driver_exit(void)
-{
-       umc_driver_unregister(&whcrc_driver);
-}
-module_exit(whcrc_driver_exit);
-
-MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
-MODULE_DESCRIPTION("Wireless Host Controller Radio Control Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/uwb/whci.c b/drivers/uwb/whci.c
deleted file mode 100644 (file)
index be8a8b8..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * WHCI UWB Multi-interface Controller enumerator.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- */
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/uwb/whci.h>
-#include <linux/uwb/umc.h>
-
-struct whci_card {
-       struct pci_dev *pci;
-       void __iomem *uwbbase;
-       u8 n_caps;
-       struct umc_dev *devs[0];
-};
-
-
-/* Fix faulty HW :( */
-static
-u64 whci_capdata_quirks(struct whci_card *card, u64 capdata)
-{
-       u64 capdata_orig = capdata;
-       struct pci_dev *pci_dev = card->pci;
-       if (pci_dev->vendor == PCI_VENDOR_ID_INTEL
-           && (pci_dev->device == 0x0c3b || pci_dev->device == 0004)
-           && pci_dev->class == 0x0d1010) {
-               switch (UWBCAPDATA_TO_CAP_ID(capdata)) {
-                       /* WLP capability has 0x100 bytes of aperture */
-               case 0x80:
-                       capdata |= 0x40 << 8; break;
-                       /* WUSB capability has 0x80 bytes of aperture
-                        * and ID is 1 */
-               case 0x02:
-                       capdata &= ~0xffff;
-                       capdata |= 0x2001;
-                       break;
-               }
-       }
-       if (capdata_orig != capdata)
-               dev_warn(&pci_dev->dev,
-                        "PCI v%04x d%04x c%06x#%02x: "
-                        "corrected capdata from %016Lx to %016Lx\n",
-                        pci_dev->vendor, pci_dev->device, pci_dev->class,
-                        (unsigned)UWBCAPDATA_TO_CAP_ID(capdata),
-                        (unsigned long long)capdata_orig,
-                        (unsigned long long)capdata);
-       return capdata;
-}
-
-
-/**
- * whci_wait_for - wait for a WHCI register to be set
- *
- * Polls (for at most @max_ms ms) until '*@reg & @mask == @result'.
- */
-int whci_wait_for(struct device *dev, u32 __iomem *reg, u32 mask, u32 result,
-       unsigned long max_ms, const char *tag)
-{
-       unsigned t = 0;
-       u32 val;
-       for (;;) {
-               val = le_readl(reg);
-               if ((val & mask) == result)
-                       break;
-               if (t >= max_ms) {
-                       dev_err(dev, "%s timed out\n", tag);
-                       return -ETIMEDOUT;
-               }
-               msleep(10);
-               t += 10;
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(whci_wait_for);
-
-
-/*
- * NOTE: the capinfo and capdata registers are slightly different
- *       (size and cap-id fields). So for cap #0, we need to fill
- *       in. Size comes from the size of the register block
- *       (statically calculated); cap_id comes from nowhere, we use
- *       zero, that is reserved, for the radio controller, because
- *       none was defined at the spec level.
- */
-static int whci_add_cap(struct whci_card *card, int n)
-{
-       struct umc_dev *umc;
-       u64 capdata;
-       int bar, err;
-
-       umc = umc_device_create(&card->pci->dev, n);
-       if (umc == NULL)
-               return -ENOMEM;
-
-       capdata = le_readq(card->uwbbase + UWBCAPDATA(n));
-
-       bar = UWBCAPDATA_TO_BAR(capdata) << 1;
-
-       capdata = whci_capdata_quirks(card, capdata);
-       /* Capability 0 is the radio controller. It's size is 32
-        * bytes (WHCI0.95[2.3, T2-9]). */
-       umc->version         = UWBCAPDATA_TO_VERSION(capdata);
-       umc->cap_id          = n == 0 ? 0 : UWBCAPDATA_TO_CAP_ID(capdata);
-       umc->bar             = bar;
-       umc->resource.start  = pci_resource_start(card->pci, bar)
-               + UWBCAPDATA_TO_OFFSET(capdata);
-       umc->resource.end    = umc->resource.start
-               + (n == 0 ? 0x20 : UWBCAPDATA_TO_SIZE(capdata)) - 1;
-       umc->resource.name   = dev_name(&umc->dev);
-       umc->resource.flags  = card->pci->resource[bar].flags;
-       umc->resource.parent = &card->pci->resource[bar];
-       umc->irq             = card->pci->irq;
-
-       err = umc_device_register(umc);
-       if (err < 0)
-               goto error;
-       card->devs[n] = umc;
-       return 0;
-
-error:
-       kfree(umc);
-       return err;
-}
-
-static void whci_del_cap(struct whci_card *card, int n)
-{
-       struct umc_dev *umc = card->devs[n];
-
-       umc_device_unregister(umc);
-}
-
-static int whci_n_caps(struct pci_dev *pci)
-{
-       void __iomem *uwbbase;
-       u64 capinfo;
-
-       uwbbase = pci_iomap(pci, 0, 8);
-       if (!uwbbase)
-               return -ENOMEM;
-       capinfo = le_readq(uwbbase + UWBCAPINFO);
-       pci_iounmap(pci, uwbbase);
-
-       return UWBCAPINFO_TO_N_CAPS(capinfo);
-}
-
-static int whci_probe(struct pci_dev *pci, const struct pci_device_id *id)
-{
-       struct whci_card *card;
-       int err, n_caps, n;
-
-       err = pci_enable_device(pci);
-       if (err < 0)
-               goto error;
-       pci_enable_msi(pci);
-       pci_set_master(pci);
-       err = -ENXIO;
-       if (!pci_set_dma_mask(pci, DMA_BIT_MASK(64)))
-               pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64));
-       else if (!pci_set_dma_mask(pci, DMA_BIT_MASK(32)))
-               pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32));
-       else
-               goto error_dma;
-
-       err = n_caps = whci_n_caps(pci);
-       if (n_caps < 0)
-               goto error_ncaps;
-
-       err = -ENOMEM;
-       card = kzalloc(sizeof(struct whci_card)
-                      + sizeof(struct umc_dev *) * (n_caps + 1),
-                      GFP_KERNEL);
-       if (card == NULL)
-               goto error_kzalloc;
-       card->pci = pci;
-       card->n_caps = n_caps;
-
-       err = -EBUSY;
-       if (!request_mem_region(pci_resource_start(pci, 0),
-                               UWBCAPDATA_SIZE(card->n_caps),
-                               "whci (capability data)"))
-               goto error_request_memregion;
-       err = -ENOMEM;
-       card->uwbbase = pci_iomap(pci, 0, UWBCAPDATA_SIZE(card->n_caps));
-       if (!card->uwbbase)
-               goto error_iomap;
-
-       /* Add each capability. */
-       for (n = 0; n <= card->n_caps; n++) {
-               err = whci_add_cap(card, n);
-               if (err < 0 && n == 0) {
-                       dev_err(&pci->dev, "cannot bind UWB radio controller:"
-                               " %d\n", err);
-                       goto error_bind;
-               }
-               if (err < 0)
-                       dev_warn(&pci->dev, "warning: cannot bind capability "
-                                "#%u: %d\n", n, err);
-       }
-       pci_set_drvdata(pci, card);
-       return 0;
-
-error_bind:
-       pci_iounmap(pci, card->uwbbase);
-error_iomap:
-       release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
-error_request_memregion:
-       kfree(card);
-error_kzalloc:
-error_ncaps:
-error_dma:
-       pci_disable_msi(pci);
-       pci_disable_device(pci);
-error:
-       return err;
-}
-
-static void whci_remove(struct pci_dev *pci)
-{
-       struct whci_card *card = pci_get_drvdata(pci);
-       int n;
-
-       pci_set_drvdata(pci, NULL);
-       /* Unregister each capability in reverse (so the master device
-        * is unregistered last). */
-       for (n = card->n_caps; n >= 0 ; n--)
-               whci_del_cap(card, n);
-       pci_iounmap(pci, card->uwbbase);
-       release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps));
-       kfree(card);
-       pci_disable_msi(pci);
-       pci_disable_device(pci);
-}
-
-static struct pci_device_id whci_id_table[] = {
-       { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
-       { 0 },
-};
-MODULE_DEVICE_TABLE(pci, whci_id_table);
-
-
-static struct pci_driver whci_driver = {
-       .name     = "whci",
-       .id_table = whci_id_table,
-       .probe    = whci_probe,
-       .remove   = whci_remove,
-};
-
-module_pci_driver(whci_driver);
-MODULE_DESCRIPTION("WHCI UWB Multi-interface Controller enumerator");
-MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
-MODULE_LICENSE("GPL");
diff --git a/include/linux/usb/association.h b/include/linux/usb/association.h
deleted file mode 100644 (file)
index d7f3cb9..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB - Cable Based Association
- *
- * Copyright (C) 2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- */
-#ifndef __LINUX_USB_ASSOCIATION_H
-#define __LINUX_USB_ASSOCIATION_H
-
-
-/*
- * Association attributes
- *
- * Association Models Supplement to WUSB 1.0 T[3-1]
- *
- * Each field in the structures has it's ID, it's length and then the
- * value. This is the actual definition of the field's ID and its
- * length.
- */
-struct wusb_am_attr {
-       __u8 id;
-       __u8 len;
-};
-
-/* Different fields defined by the spec */
-#define WUSB_AR_AssociationTypeId      { .id = cpu_to_le16(0x0000), .len = cpu_to_le16(2) }
-#define WUSB_AR_AssociationSubTypeId   { .id = cpu_to_le16(0x0001), .len = cpu_to_le16(2) }
-#define WUSB_AR_Length                 { .id = cpu_to_le16(0x0002), .len = cpu_to_le16(4) }
-#define WUSB_AR_AssociationStatus      { .id = cpu_to_le16(0x0004), .len = cpu_to_le16(4) }
-#define WUSB_AR_LangID                 { .id = cpu_to_le16(0x0008), .len = cpu_to_le16(2) }
-#define WUSB_AR_DeviceFriendlyName     { .id = cpu_to_le16(0x000b), .len = cpu_to_le16(64) } /* max */
-#define WUSB_AR_HostFriendlyName       { .id = cpu_to_le16(0x000c), .len = cpu_to_le16(64) } /* max */
-#define WUSB_AR_CHID                   { .id = cpu_to_le16(0x1000), .len = cpu_to_le16(16) }
-#define WUSB_AR_CDID                   { .id = cpu_to_le16(0x1001), .len = cpu_to_le16(16) }
-#define WUSB_AR_ConnectionContext      { .id = cpu_to_le16(0x1002), .len = cpu_to_le16(48) }
-#define WUSB_AR_BandGroups             { .id = cpu_to_le16(0x1004), .len = cpu_to_le16(2) }
-
-/* CBAF Control Requests (AMS1.0[T4-1] */
-enum {
-       CBAF_REQ_GET_ASSOCIATION_INFORMATION = 0x01,
-       CBAF_REQ_GET_ASSOCIATION_REQUEST,
-       CBAF_REQ_SET_ASSOCIATION_RESPONSE
-};
-
-/*
- * CBAF USB-interface defitions
- *
- * No altsettings, one optional interrupt endpoint.
- */
-enum {
-       CBAF_IFACECLASS    = 0xef,
-       CBAF_IFACESUBCLASS = 0x03,
-       CBAF_IFACEPROTOCOL = 0x01,
-};
-
-/* Association Information (AMS1.0[T4-3]) */
-struct wusb_cbaf_assoc_info {
-       __le16 Length;
-       __u8 NumAssociationRequests;
-       __le16 Flags;
-       __u8 AssociationRequestsArray[];
-} __attribute__((packed));
-
-/* Association Request (AMS1.0[T4-4]) */
-struct wusb_cbaf_assoc_request {
-       __u8 AssociationDataIndex;
-       __u8 Reserved;
-       __le16 AssociationTypeId;
-       __le16 AssociationSubTypeId;
-       __le32 AssociationTypeInfoSize;
-} __attribute__((packed));
-
-enum {
-       AR_TYPE_WUSB                    = 0x0001,
-       AR_TYPE_WUSB_RETRIEVE_HOST_INFO = 0x0000,
-       AR_TYPE_WUSB_ASSOCIATE          = 0x0001,
-};
-
-/* Association Attribute header (AMS1.0[3.8]) */
-struct wusb_cbaf_attr_hdr {
-       __le16 id;
-       __le16 len;
-} __attribute__((packed));
-
-/* Host Info (AMS1.0[T4-7]) (yeah, more headers and fields...) */
-struct wusb_cbaf_host_info {
-       struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
-       __le16 AssociationTypeId;
-       struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
-       __le16 AssociationSubTypeId;
-       struct wusb_cbaf_attr_hdr CHID_hdr;
-       struct wusb_ckhdid CHID;
-       struct wusb_cbaf_attr_hdr LangID_hdr;
-       __le16 LangID;
-       struct wusb_cbaf_attr_hdr HostFriendlyName_hdr;
-       __u8 HostFriendlyName[];
-} __attribute__((packed));
-
-/* Device Info (AMS1.0[T4-8])
- *
- * I still don't get this tag'n'header stuff for each goddamn
- * field...
- */
-struct wusb_cbaf_device_info {
-       struct wusb_cbaf_attr_hdr Length_hdr;
-       __le32 Length;
-       struct wusb_cbaf_attr_hdr CDID_hdr;
-       struct wusb_ckhdid CDID;
-       struct wusb_cbaf_attr_hdr BandGroups_hdr;
-       __le16 BandGroups;
-       struct wusb_cbaf_attr_hdr LangID_hdr;
-       __le16 LangID;
-       struct wusb_cbaf_attr_hdr DeviceFriendlyName_hdr;
-       __u8 DeviceFriendlyName[];
-} __attribute__((packed));
-
-/* Connection Context; CC_DATA - Success case (AMS1.0[T4-9]) */
-struct wusb_cbaf_cc_data {
-       struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
-       __le16 AssociationTypeId;
-       struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
-       __le16 AssociationSubTypeId;
-       struct wusb_cbaf_attr_hdr Length_hdr;
-       __le32 Length;
-       struct wusb_cbaf_attr_hdr ConnectionContext_hdr;
-       struct wusb_ckhdid CHID;
-       struct wusb_ckhdid CDID;
-       struct wusb_ckhdid CK;
-       struct wusb_cbaf_attr_hdr BandGroups_hdr;
-       __le16 BandGroups;
-} __attribute__((packed));
-
-/* CC_DATA - Failure case (AMS1.0[T4-10]) */
-struct wusb_cbaf_cc_data_fail {
-       struct wusb_cbaf_attr_hdr AssociationTypeId_hdr;
-       __le16 AssociationTypeId;
-       struct wusb_cbaf_attr_hdr AssociationSubTypeId_hdr;
-       __le16 AssociationSubTypeId;
-       struct wusb_cbaf_attr_hdr Length_hdr;
-       __le16 Length;
-       struct wusb_cbaf_attr_hdr AssociationStatus_hdr;
-       __u32 AssociationStatus;
-} __attribute__((packed));
-
-#endif /* __LINUX_USB_ASSOCIATION_H */
diff --git a/include/linux/usb/wusb-wa.h b/include/linux/usb/wusb-wa.h
deleted file mode 100644 (file)
index 64a840b..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Wire Adapter constants and structures.
- *
- * Copyright (C) 2005-2006 Intel Corporation.
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- * FIXME: organize properly, group logically
- *
- * All the event structures are defined in uwb/spec.h, as they are
- * common to the WHCI and WUSB radio control interfaces.
- *
- * References:
- *   [WUSB] Wireless Universal Serial Bus Specification, revision 1.0, ch8
- */
-#ifndef __LINUX_USB_WUSB_WA_H
-#define __LINUX_USB_WUSB_WA_H
-
-/**
- * Radio Command Request for the Radio Control Interface
- *
- * Radio Control Interface command and event codes are the same as
- * WHCI, and listed in include/linux/uwb.h:UWB_RC_{CMD,EVT}_*
- */
-enum {
-       WA_EXEC_RC_CMD = 40,    /* Radio Control command Request */
-};
-
-/* Wireless Adapter Requests ([WUSB] table 8-51) */
-enum {
-       WUSB_REQ_ADD_MMC_IE     = 20,
-       WUSB_REQ_REMOVE_MMC_IE  = 21,
-       WUSB_REQ_SET_NUM_DNTS   = 22,
-       WUSB_REQ_SET_CLUSTER_ID = 23,
-       WUSB_REQ_SET_DEV_INFO   = 24,
-       WUSB_REQ_GET_TIME       = 25,
-       WUSB_REQ_SET_STREAM_IDX = 26,
-       WUSB_REQ_SET_WUSB_MAS   = 27,
-       WUSB_REQ_CHAN_STOP      = 28,
-};
-
-
-/* Wireless Adapter WUSB Channel Time types ([WUSB] table 8-52) */
-enum {
-       WUSB_TIME_ADJ   = 0,
-       WUSB_TIME_BPST  = 1,
-       WUSB_TIME_WUSB  = 2,
-};
-
-enum {
-       WA_ENABLE = 0x01,
-       WA_RESET = 0x02,
-       RPIPE_PAUSE = 0x1,
-       RPIPE_STALL = 0x2,
-};
-
-/* Responses from Get Status request ([WUSB] section 8.3.1.6) */
-enum {
-       WA_STATUS_ENABLED = 0x01,
-       WA_STATUS_RESETTING = 0x02
-};
-
-enum rpipe_crs {
-       RPIPE_CRS_CTL = 0x01,
-       RPIPE_CRS_ISO = 0x02,
-       RPIPE_CRS_BULK = 0x04,
-       RPIPE_CRS_INTR = 0x08
-};
-
-/**
- * RPipe descriptor ([WUSB] section 8.5.2.11)
- *
- * FIXME: explain rpipes
- */
-struct usb_rpipe_descriptor {
-       u8      bLength;
-       u8      bDescriptorType;
-       __le16  wRPipeIndex;
-       __le16  wRequests;
-       __le16  wBlocks;                /* rw if 0 */
-       __le16  wMaxPacketSize;         /* rw */
-       union {
-               u8      dwa_bHSHubAddress;              /* rw: DWA. */
-               u8      hwa_bMaxBurst;                  /* rw: HWA. */
-       };
-       union {
-               u8      dwa_bHSHubPort;         /*  rw: DWA. */
-               u8      hwa_bDeviceInfoIndex;   /*  rw: HWA. */
-       };
-       u8      bSpeed;                 /* rw: xfer rate 'enum uwb_phy_rate' */
-       union {
-               u8 dwa_bDeviceAddress;  /* rw: DWA Target device address. */
-               u8 hwa_reserved;                /* rw: HWA. */
-       };
-       u8      bEndpointAddress;       /* rw: Target EP address */
-       u8      bDataSequence;          /* ro: Current Data sequence */
-       __le32  dwCurrentWindow;        /* ro */
-       u8      bMaxDataSequence;       /* ro?: max supported seq */
-       u8      bInterval;              /* rw:  */
-       u8      bOverTheAirInterval;    /* rw:  */
-       u8      bmAttribute;            /* ro?  */
-       u8      bmCharacteristics;      /* ro? enum rpipe_attr, supported xsactions */
-       u8      bmRetryOptions;         /* rw? */
-       __le16  wNumTransactionErrors;  /* rw */
-} __attribute__ ((packed));
-
-/**
- * Wire Adapter Notification types ([WUSB] sections 8.4.5 & 8.5.4)
- *
- * These are the notifications coming on the notification endpoint of
- * an HWA and a DWA.
- */
-enum wa_notif_type {
-       DWA_NOTIF_RWAKE = 0x91,
-       DWA_NOTIF_PORTSTATUS = 0x92,
-       WA_NOTIF_TRANSFER = 0x93,
-       HWA_NOTIF_BPST_ADJ = 0x94,
-       HWA_NOTIF_DN = 0x95,
-};
-
-/**
- * Wire Adapter notification header
- *
- * Notifications coming from a wire adapter use a common header
- * defined in [WUSB] sections 8.4.5 & 8.5.4.
- */
-struct wa_notif_hdr {
-       u8 bLength;
-       u8 bNotifyType;                 /* enum wa_notif_type */
-} __packed;
-
-/**
- * HWA DN Received notification [(WUSB] section 8.5.4.2)
- *
- * The DNData is specified in WUSB1.0[7.6]. For each device
- * notification we received, we just need to dispatch it.
- *
- * @dndata:  this is really an array of notifications, but all start
- *           with the same header.
- */
-struct hwa_notif_dn {
-       struct wa_notif_hdr hdr;
-       u8 bSourceDeviceAddr;           /* from errata 2005/07 */
-       u8 bmAttributes;
-       struct wusb_dn_hdr dndata[];
-} __packed;
-
-/* [WUSB] section 8.3.3 */
-enum wa_xfer_type {
-       WA_XFER_TYPE_CTL = 0x80,
-       WA_XFER_TYPE_BI = 0x81,         /* bulk/interrupt */
-       WA_XFER_TYPE_ISO = 0x82,
-       WA_XFER_RESULT = 0x83,
-       WA_XFER_ABORT = 0x84,
-       WA_XFER_ISO_PACKET_INFO = 0xA0,
-       WA_XFER_ISO_PACKET_STATUS = 0xA1,
-};
-
-/* [WUSB] section 8.3.3 */
-struct wa_xfer_hdr {
-       u8 bLength;                     /* 0x18 */
-       u8 bRequestType;                /* 0x80 WA_REQUEST_TYPE_CTL */
-       __le16 wRPipe;                  /* RPipe index */
-       __le32 dwTransferID;            /* Host-assigned ID */
-       __le32 dwTransferLength;        /* Length of data to xfer */
-       u8 bTransferSegment;
-} __packed;
-
-struct wa_xfer_ctl {
-       struct wa_xfer_hdr hdr;
-       u8 bmAttribute;
-       __le16 wReserved;
-       struct usb_ctrlrequest baSetupData;
-} __packed;
-
-struct wa_xfer_bi {
-       struct wa_xfer_hdr hdr;
-       u8 bReserved;
-       __le16 wReserved;
-} __packed;
-
-/* [WUSB] section 8.5.5 */
-struct wa_xfer_hwaiso {
-       struct wa_xfer_hdr hdr;
-       u8 bReserved;
-       __le16 wPresentationTime;
-       __le32 dwNumOfPackets;
-} __packed;
-
-struct wa_xfer_packet_info_hwaiso {
-       __le16 wLength;
-       u8 bPacketType;
-       u8 bReserved;
-       __le16 PacketLength[0];
-} __packed;
-
-struct wa_xfer_packet_status_len_hwaiso {
-       __le16 PacketLength;
-       __le16 PacketStatus;
-} __packed;
-
-struct wa_xfer_packet_status_hwaiso {
-       __le16 wLength;
-       u8 bPacketType;
-       u8 bReserved;
-       struct wa_xfer_packet_status_len_hwaiso PacketStatus[0];
-} __packed;
-
-/* [WUSB] section 8.3.3.5 */
-struct wa_xfer_abort {
-       u8 bLength;
-       u8 bRequestType;
-       __le16 wRPipe;                  /* RPipe index */
-       __le32 dwTransferID;            /* Host-assigned ID */
-} __packed;
-
-/**
- * WA Transfer Complete notification ([WUSB] section 8.3.3.3)
- *
- */
-struct wa_notif_xfer {
-       struct wa_notif_hdr hdr;
-       u8 bEndpoint;
-       u8 Reserved;
-} __packed;
-
-/** Transfer result basic codes [WUSB] table 8-15 */
-enum {
-       WA_XFER_STATUS_SUCCESS,
-       WA_XFER_STATUS_HALTED,
-       WA_XFER_STATUS_DATA_BUFFER_ERROR,
-       WA_XFER_STATUS_BABBLE,
-       WA_XFER_RESERVED,
-       WA_XFER_STATUS_NOT_FOUND,
-       WA_XFER_STATUS_INSUFFICIENT_RESOURCE,
-       WA_XFER_STATUS_TRANSACTION_ERROR,
-       WA_XFER_STATUS_ABORTED,
-       WA_XFER_STATUS_RPIPE_NOT_READY,
-       WA_XFER_INVALID_FORMAT,
-       WA_XFER_UNEXPECTED_SEGMENT_NUMBER,
-       WA_XFER_STATUS_RPIPE_TYPE_MISMATCH,
-};
-
-/** [WUSB] section 8.3.3.4 */
-struct wa_xfer_result {
-       struct wa_notif_hdr hdr;
-       __le32 dwTransferID;
-       __le32 dwTransferLength;
-       u8     bTransferSegment;
-       u8     bTransferStatus;
-       __le32 dwNumOfPackets;
-} __packed;
-
-/**
- * Wire Adapter Class Descriptor ([WUSB] section 8.5.2.7).
- *
- * NOTE: u16 fields are read Little Endian from the hardware.
- *
- * @bNumPorts is the original max number of devices that the host can
- *            connect; we might chop this so the stack can handle
- *            it. In case you need to access it, use wusbhc->ports_max
- *            if it is a Wireless USB WA.
- */
-struct usb_wa_descriptor {
-       u8      bLength;
-       u8      bDescriptorType;
-       __le16  bcdWAVersion;
-       u8      bNumPorts;              /* don't use!! */
-       u8      bmAttributes;           /* Reserved == 0 */
-       __le16  wNumRPipes;
-       __le16  wRPipeMaxBlock;
-       u8      bRPipeBlockSize;
-       u8      bPwrOn2PwrGood;
-       u8      bNumMMCIEs;
-       u8      DeviceRemovable;        /* FIXME: in DWA this is up to 16 bytes */
-} __packed;
-
-/**
- * HWA Device Information Buffer (WUSB1.0[T8.54])
- */
-struct hwa_dev_info {
-       u8      bmDeviceAvailability[32];       /* FIXME: ignored for now */
-       u8      bDeviceAddress;
-       __le16  wPHYRates;
-       u8      bmDeviceAttribute;
-} __packed;
-
-#endif /* #ifndef __LINUX_USB_WUSB_WA_H */
diff --git a/include/linux/usb/wusb.h b/include/linux/usb/wusb.h
deleted file mode 100644 (file)
index 65adee6..0000000
+++ /dev/null
@@ -1,362 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Wireless USB Standard Definitions
- * Event Size Tables
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- *
- * FIXME: docs
- * FIXME: organize properly, group logically
- *
- * All the event structures are defined in uwb/spec.h, as they are
- * common to the WHCI and WUSB radio control interfaces.
- */
-
-#ifndef __WUSB_H__
-#define __WUSB_H__
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/uwb/spec.h>
-#include <linux/usb/ch9.h>
-#include <linux/param.h>
-
-/**
- * WUSB Information Element header
- *
- * I don't know why, they decided to make it different to the MBOA MAC
- * IE Header; beats me.
- */
-struct wuie_hdr {
-       u8 bLength;
-       u8 bIEIdentifier;
-} __attribute__((packed));
-
-enum {
-       WUIE_ID_WCTA = 0x80,
-       WUIE_ID_CONNECTACK,
-       WUIE_ID_HOST_INFO,
-       WUIE_ID_CHANGE_ANNOUNCE,
-       WUIE_ID_DEVICE_DISCONNECT,
-       WUIE_ID_HOST_DISCONNECT,
-       WUIE_ID_KEEP_ALIVE = 0x89,
-       WUIE_ID_ISOCH_DISCARD,
-       WUIE_ID_RESET_DEVICE,
-};
-
-/**
- * Maximum number of array elements in a WUSB IE.
- *
- * WUSB1.0[7.5 before table 7-38] says that in WUSB IEs that
- * are "arrays" have to limited to 4 elements. So we define it
- * like that to ease up and submit only the neeed size.
- */
-#define WUIE_ELT_MAX 4
-
-/**
- * Wrapper for the data that defines a CHID, a CDID or a CK
- *
- * WUSB defines that CHIDs, CDIDs and CKs are a 16 byte string of
- * data. In order to avoid confusion and enforce types, we wrap it.
- *
- * Make it packed, as we use it in some hw definitions.
- */
-struct wusb_ckhdid {
-       u8 data[16];
-} __attribute__((packed));
-
-static const struct wusb_ckhdid wusb_ckhdid_zero = { .data = { 0 } };
-
-#define WUSB_CKHDID_STRSIZE (3 * sizeof(struct wusb_ckhdid) + 1)
-
-/**
- * WUSB IE: Host Information (WUSB1.0[7.5.2])
- *
- * Used to provide information about the host to the Wireless USB
- * devices in range (CHID can be used as an ASCII string).
- */
-struct wuie_host_info {
-       struct wuie_hdr hdr;
-       __le16 attributes;
-       struct wusb_ckhdid CHID;
-} __attribute__((packed));
-
-/**
- * WUSB IE: Connect Ack (WUSB1.0[7.5.1])
- *
- * Used to acknowledge device connect requests. See note for
- * WUIE_ELT_MAX.
- */
-struct wuie_connect_ack {
-       struct wuie_hdr hdr;
-       struct {
-               struct wusb_ckhdid CDID;
-               u8 bDeviceAddress;      /* 0 means unused */
-               u8 bReserved;
-       } blk[WUIE_ELT_MAX];
-} __attribute__((packed));
-
-/**
- * WUSB IE Host Information Element, Connect Availability
- *
- * WUSB1.0[7.5.2], bmAttributes description
- */
-enum {
-       WUIE_HI_CAP_RECONNECT = 0,
-       WUIE_HI_CAP_LIMITED,
-       WUIE_HI_CAP_RESERVED,
-       WUIE_HI_CAP_ALL,
-};
-
-/**
- * WUSB IE: Channel Stop (WUSB1.0[7.5.8])
- *
- * Tells devices the host is going to stop sending MMCs and will disappear.
- */
-struct wuie_channel_stop {
-       struct wuie_hdr hdr;
-       u8 attributes;
-       u8 timestamp[3];
-} __attribute__((packed));
-
-/**
- * WUSB IE: Keepalive (WUSB1.0[7.5.9])
- *
- * Ask device(s) to send keepalives.
- */
-struct wuie_keep_alive {
-       struct wuie_hdr hdr;
-       u8 bDeviceAddress[WUIE_ELT_MAX];
-} __attribute__((packed));
-
-/**
- * WUSB IE: Reset device (WUSB1.0[7.5.11])
- *
- * Tell device to reset; in all truth, we can fit 4 CDIDs, but we only
- * use it for one at the time...
- *
- * In any case, this request is a wee bit silly: why don't they target
- * by address??
- */
-struct wuie_reset {
-       struct wuie_hdr hdr;
-       struct wusb_ckhdid CDID;
-} __attribute__((packed));
-
-/**
- * WUSB IE: Disconnect device (WUSB1.0[7.5.11])
- *
- * Tell device to disconnect; we can fit 4 addresses, but we only use
- * it for one at the time...
- */
-struct wuie_disconnect {
-       struct wuie_hdr hdr;
-       u8 bDeviceAddress;
-       u8 padding;
-} __attribute__((packed));
-
-/**
- * WUSB IE: Host disconnect ([WUSB] section 7.5.5)
- *
- * Tells all connected devices to disconnect.
- */
-struct wuie_host_disconnect {
-       struct wuie_hdr hdr;
-} __attribute__((packed));
-
-/**
- * WUSB Device Notification header (WUSB1.0[7.6])
- */
-struct wusb_dn_hdr {
-       u8 bType;
-       u8 notifdata[];
-} __attribute__((packed));
-
-/** Device Notification codes (WUSB1.0[Table 7-54]) */
-enum WUSB_DN {
-       WUSB_DN_CONNECT = 0x01,
-       WUSB_DN_DISCONNECT = 0x02,
-       WUSB_DN_EPRDY = 0x03,
-       WUSB_DN_MASAVAILCHANGED = 0x04,
-       WUSB_DN_RWAKE = 0x05,
-       WUSB_DN_SLEEP = 0x06,
-       WUSB_DN_ALIVE = 0x07,
-};
-
-/** WUSB Device Notification Connect */
-struct wusb_dn_connect {
-       struct wusb_dn_hdr hdr;
-       __le16 attributes;
-       struct wusb_ckhdid CDID;
-} __attribute__((packed));
-
-static inline int wusb_dn_connect_prev_dev_addr(const struct wusb_dn_connect *dn)
-{
-       return le16_to_cpu(dn->attributes) & 0xff;
-}
-
-static inline int wusb_dn_connect_new_connection(const struct wusb_dn_connect *dn)
-{
-       return (le16_to_cpu(dn->attributes) >> 8) & 0x1;
-}
-
-static inline int wusb_dn_connect_beacon_behavior(const struct wusb_dn_connect *dn)
-{
-       return (le16_to_cpu(dn->attributes) >> 9) & 0x03;
-}
-
-/** Device is alive (aka: pong) (WUSB1.0[7.6.7]) */
-struct wusb_dn_alive {
-       struct wusb_dn_hdr hdr;
-} __attribute__((packed));
-
-/** Device is disconnecting (WUSB1.0[7.6.2]) */
-struct wusb_dn_disconnect {
-       struct wusb_dn_hdr hdr;
-} __attribute__((packed));
-
-/* General constants */
-enum {
-       WUSB_TRUST_TIMEOUT_MS = 4000,   /* [WUSB] section 4.15.1 */
-};
-
-/*
- * WUSB Crypto stuff (WUSB1.0[6])
- */
-
-extern const char *wusb_et_name(u8);
-
-/**
- * WUSB key index WUSB1.0[7.3.2.4], for usage when setting keys for
- * the host or the device.
- */
-static inline u8 wusb_key_index(int index, int type, int originator)
-{
-       return (originator << 6) | (type << 4) | index;
-}
-
-#define WUSB_KEY_INDEX_TYPE_PTK                        0 /* for HWA only */
-#define WUSB_KEY_INDEX_TYPE_ASSOC              1
-#define WUSB_KEY_INDEX_TYPE_GTK                        2
-#define WUSB_KEY_INDEX_ORIGINATOR_HOST         0
-#define WUSB_KEY_INDEX_ORIGINATOR_DEVICE       1
-/* bits 0-3 used for the key index. */
-#define WUSB_KEY_INDEX_MAX                     15
-
-/* A CCM Nonce, defined in WUSB1.0[6.4.1] */
-struct aes_ccm_nonce {
-       u8 sfn[6];              /* Little Endian */
-       u8 tkid[3];             /* LE */
-       struct uwb_dev_addr dest_addr;
-       struct uwb_dev_addr src_addr;
-} __attribute__((packed));
-
-/* A CCM operation label, defined on WUSB1.0[6.5.x] */
-struct aes_ccm_label {
-       u8 data[14];
-} __attribute__((packed));
-
-/*
- * Input to the key derivation sequence defined in
- * WUSB1.0[6.5.1]. Rest of the data is in the CCM Nonce passed to the
- * PRF function.
- */
-struct wusb_keydvt_in {
-       u8 hnonce[16];
-       u8 dnonce[16];
-} __attribute__((packed));
-
-/*
- * Output from the key derivation sequence defined in
- * WUSB1.0[6.5.1].
- */
-struct wusb_keydvt_out {
-       u8 kck[16];
-       u8 ptk[16];
-} __attribute__((packed));
-
-/* Pseudo Random Function WUSB1.0[6.5] */
-extern int wusb_crypto_init(void);
-extern void wusb_crypto_exit(void);
-extern ssize_t wusb_prf(void *out, size_t out_size,
-                       const u8 key[16], const struct aes_ccm_nonce *_n,
-                       const struct aes_ccm_label *a,
-                       const void *b, size_t blen, size_t len);
-
-static inline int wusb_prf_64(void *out, size_t out_size, const u8 key[16],
-                             const struct aes_ccm_nonce *n,
-                             const struct aes_ccm_label *a,
-                             const void *b, size_t blen)
-{
-       return wusb_prf(out, out_size, key, n, a, b, blen, 64);
-}
-
-static inline int wusb_prf_128(void *out, size_t out_size, const u8 key[16],
-                              const struct aes_ccm_nonce *n,
-                              const struct aes_ccm_label *a,
-                              const void *b, size_t blen)
-{
-       return wusb_prf(out, out_size, key, n, a, b, blen, 128);
-}
-
-static inline int wusb_prf_256(void *out, size_t out_size, const u8 key[16],
-                              const struct aes_ccm_nonce *n,
-                              const struct aes_ccm_label *a,
-                              const void *b, size_t blen)
-{
-       return wusb_prf(out, out_size, key, n, a, b, blen, 256);
-}
-
-/* Key derivation WUSB1.0[6.5.1] */
-static inline int wusb_key_derive(struct wusb_keydvt_out *keydvt_out,
-                                 const u8 key[16],
-                                 const struct aes_ccm_nonce *n,
-                                 const struct wusb_keydvt_in *keydvt_in)
-{
-       const struct aes_ccm_label a = { .data = "Pair-wise keys" };
-       return wusb_prf_256(keydvt_out, sizeof(*keydvt_out), key, n, &a,
-                           keydvt_in, sizeof(*keydvt_in));
-}
-
-/*
- * Out-of-band MIC Generation WUSB1.0[6.5.2]
- *
- * Compute the MIC over @key, @n and @hs and place it in @mic_out.
- *
- * @mic_out:  Where to place the 8 byte MIC tag
- * @key:      KCK from the derivation process
- * @n:        CCM nonce, n->sfn == 0, TKID as established in the
- *            process.
- * @hs:       Handshake struct for phase 2 of the 4-way.
- *            hs->bStatus and hs->bReserved are zero.
- *            hs->bMessageNumber is 2 (WUSB1.0[7.3.2.5.2]
- *            hs->dest_addr is the device's USB address padded with 0
- *            hs->src_addr is the hosts's UWB device address
- *            hs->mic is ignored (as we compute that value).
- */
-static inline int wusb_oob_mic(u8 mic_out[8], const u8 key[16],
-                              const struct aes_ccm_nonce *n,
-                              const struct usb_handshake *hs)
-{
-       const struct aes_ccm_label a = { .data = "out-of-bandMIC" };
-       return wusb_prf_64(mic_out, 8, key, n, &a,
-                          hs, sizeof(*hs) - sizeof(hs->MIC));
-}
-
-#endif /* #ifndef __WUSB_H__ */
diff --git a/include/linux/uwb.h b/include/linux/uwb.h
deleted file mode 100644 (file)
index 6918a61..0000000
+++ /dev/null
@@ -1,817 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Ultra Wide Band
- * UWB API
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * FIXME: doc: overview of the API, different parts and pointers
- */
-
-#ifndef __LINUX__UWB_H__
-#define __LINUX__UWB_H__
-
-#include <linux/limits.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
-#include <linux/uwb/spec.h>
-#include <asm/page.h>
-
-struct uwb_dev;
-struct uwb_beca_e;
-struct uwb_rc;
-struct uwb_rsv;
-struct uwb_dbg;
-
-/**
- * struct uwb_dev - a UWB Device
- * @rc: UWB Radio Controller that discovered the device (kind of its
- *     parent).
- * @bce: a beacon cache entry for this device; or NULL if the device
- *     is a local radio controller.
- * @mac_addr: the EUI-48 address of this device.
- * @dev_addr: the current DevAddr used by this device.
- * @beacon_slot: the slot number the beacon is using.
- * @streams: bitmap of streams allocated to reservations targeted at
- *     this device.  For an RC, this is the streams allocated for
- *     reservations targeted at DevAddrs.
- *
- * A UWB device may either by a neighbor or part of a local radio
- * controller.
- */
-struct uwb_dev {
-       struct mutex mutex;
-       struct list_head list_node;
-       struct device dev;
-       struct uwb_rc *rc;              /* radio controller */
-       struct uwb_beca_e *bce;         /* Beacon Cache Entry */
-
-       struct uwb_mac_addr mac_addr;
-       struct uwb_dev_addr dev_addr;
-       int beacon_slot;
-       DECLARE_BITMAP(streams, UWB_NUM_STREAMS);
-       DECLARE_BITMAP(last_availability_bm, UWB_NUM_MAS);
-};
-#define to_uwb_dev(d) container_of(d, struct uwb_dev, dev)
-
-/**
- * UWB HWA/WHCI Radio Control {Command|Event} Block context IDs
- *
- * RC[CE]Bs have a 'context ID' field that matches the command with
- * the event received to confirm it.
- *
- * Maximum number of context IDs
- */
-enum { UWB_RC_CTX_MAX = 256 };
-
-
-/** Notification chain head for UWB generated events to listeners */
-struct uwb_notifs_chain {
-       struct list_head list;
-       struct mutex mutex;
-};
-
-/* Beacon cache list */
-struct uwb_beca {
-       struct list_head list;
-       size_t entries;
-       struct mutex mutex;
-};
-
-/* Event handling thread. */
-struct uwbd {
-       int pid;
-       struct task_struct *task;
-       wait_queue_head_t wq;
-       struct list_head event_list;
-       spinlock_t event_list_lock;
-};
-
-/**
- * struct uwb_mas_bm - a bitmap of all MAS in a superframe
- * @bm: a bitmap of length #UWB_NUM_MAS
- */
-struct uwb_mas_bm {
-       DECLARE_BITMAP(bm, UWB_NUM_MAS);
-       DECLARE_BITMAP(unsafe_bm, UWB_NUM_MAS);
-       int safe;
-       int unsafe;
-};
-
-/**
- * uwb_rsv_state - UWB Reservation state.
- *
- * NONE - reservation is not active (no DRP IE being transmitted).
- *
- * Owner reservation states:
- *
- * INITIATED - owner has sent an initial DRP request.
- * PENDING - target responded with pending Reason Code.
- * MODIFIED - reservation manager is modifying an established
- * reservation with a different MAS allocation.
- * ESTABLISHED - the reservation has been successfully negotiated.
- *
- * Target reservation states:
- *
- * DENIED - request is denied.
- * ACCEPTED - request is accepted.
- * PENDING - PAL has yet to make a decision to whether to accept or
- * deny.
- *
- * FIXME: further target states TBD.
- */
-enum uwb_rsv_state {
-       UWB_RSV_STATE_NONE = 0,
-       UWB_RSV_STATE_O_INITIATED,
-       UWB_RSV_STATE_O_PENDING,
-       UWB_RSV_STATE_O_MODIFIED,
-       UWB_RSV_STATE_O_ESTABLISHED,
-       UWB_RSV_STATE_O_TO_BE_MOVED,
-       UWB_RSV_STATE_O_MOVE_EXPANDING,
-       UWB_RSV_STATE_O_MOVE_COMBINING,
-       UWB_RSV_STATE_O_MOVE_REDUCING,
-       UWB_RSV_STATE_T_ACCEPTED,
-       UWB_RSV_STATE_T_DENIED,
-       UWB_RSV_STATE_T_CONFLICT,
-       UWB_RSV_STATE_T_PENDING,
-       UWB_RSV_STATE_T_EXPANDING_ACCEPTED,
-       UWB_RSV_STATE_T_EXPANDING_CONFLICT,
-       UWB_RSV_STATE_T_EXPANDING_PENDING,
-       UWB_RSV_STATE_T_EXPANDING_DENIED,
-       UWB_RSV_STATE_T_RESIZED,
-
-       UWB_RSV_STATE_LAST,
-};
-
-enum uwb_rsv_target_type {
-       UWB_RSV_TARGET_DEV,
-       UWB_RSV_TARGET_DEVADDR,
-};
-
-/**
- * struct uwb_rsv_target - the target of a reservation.
- *
- * Reservations unicast and targeted at a single device
- * (UWB_RSV_TARGET_DEV); or (e.g., in the case of WUSB) targeted at a
- * specific (private) DevAddr (UWB_RSV_TARGET_DEVADDR).
- */
-struct uwb_rsv_target {
-       enum uwb_rsv_target_type type;
-       union {
-               struct uwb_dev *dev;
-               struct uwb_dev_addr devaddr;
-       };
-};
-
-struct uwb_rsv_move {
-       struct uwb_mas_bm final_mas;
-       struct uwb_ie_drp *companion_drp_ie;
-       struct uwb_mas_bm companion_mas;
-};
-
-/*
- * Number of streams reserved for reservations targeted at DevAddrs.
- */
-#define UWB_NUM_GLOBAL_STREAMS 1
-
-typedef void (*uwb_rsv_cb_f)(struct uwb_rsv *rsv);
-
-/**
- * struct uwb_rsv - a DRP reservation
- *
- * Data structure management:
- *
- * @rc:             the radio controller this reservation is for
- *                  (as target or owner)
- * @rc_node:        a list node for the RC
- * @pal_node:       a list node for the PAL
- *
- * Owner and target parameters:
- *
- * @owner:          the UWB device owning this reservation
- * @target:         the target UWB device
- * @type:           reservation type
- *
- * Owner parameters:
- *
- * @max_mas:        maxiumum number of MAS
- * @min_mas:        minimum number of MAS
- * @sparsity:       owner selected sparsity
- * @is_multicast:   true iff multicast
- *
- * @callback:       callback function when the reservation completes
- * @pal_priv:       private data for the PAL making the reservation
- *
- * Reservation status:
- *
- * @status:         negotiation status
- * @stream:         stream index allocated for this reservation
- * @tiebreaker:     conflict tiebreaker for this reservation
- * @mas:            reserved MAS
- * @drp_ie:         the DRP IE
- * @ie_valid:       true iff the DRP IE matches the reservation parameters
- *
- * DRP reservations are uniquely identified by the owner, target and
- * stream index.  However, when using a DevAddr as a target (e.g., for
- * a WUSB cluster reservation) the responses may be received from
- * devices with different DevAddrs.  In this case, reservations are
- * uniquely identified by just the stream index.  A number of stream
- * indexes (UWB_NUM_GLOBAL_STREAMS) are reserved for this.
- */
-struct uwb_rsv {
-       struct uwb_rc *rc;
-       struct list_head rc_node;
-       struct list_head pal_node;
-       struct kref kref;
-
-       struct uwb_dev *owner;
-       struct uwb_rsv_target target;
-       enum uwb_drp_type type;
-       int max_mas;
-       int min_mas;
-       int max_interval;
-       bool is_multicast;
-
-       uwb_rsv_cb_f callback;
-       void *pal_priv;
-
-       enum uwb_rsv_state state;
-       bool needs_release_companion_mas;
-       u8 stream;
-       u8 tiebreaker;
-       struct uwb_mas_bm mas;
-       struct uwb_ie_drp *drp_ie;
-       struct uwb_rsv_move mv;
-       bool ie_valid;
-       struct timer_list timer;
-       struct work_struct handle_timeout_work;
-};
-
-static const
-struct uwb_mas_bm uwb_mas_bm_zero = { .bm = { 0 } };
-
-static inline void uwb_mas_bm_copy_le(void *dst, const struct uwb_mas_bm *mas)
-{
-       bitmap_copy_le(dst, mas->bm, UWB_NUM_MAS);
-}
-
-/**
- * struct uwb_drp_avail - a radio controller's view of MAS usage
- * @global:   MAS unused by neighbors (excluding reservations targeted
- *            or owned by the local radio controller) or the beaon period
- * @local:    MAS unused by local established reservations
- * @pending:  MAS unused by local pending reservations
- * @ie:       DRP Availability IE to be included in the beacon
- * @ie_valid: true iff @ie is valid and does not need to regenerated from
- *            @global and @local
- *
- * Each radio controller maintains a view of MAS usage or
- * availability. MAS available for a new reservation are determined
- * from the intersection of @global, @local, and @pending.
- *
- * The radio controller must transmit a DRP Availability IE that's the
- * intersection of @global and @local.
- *
- * A set bit indicates the MAS is unused and available.
- *
- * rc->rsvs_mutex should be held before accessing this data structure.
- *
- * [ECMA-368] section 17.4.3.
- */
-struct uwb_drp_avail {
-       DECLARE_BITMAP(global, UWB_NUM_MAS);
-       DECLARE_BITMAP(local, UWB_NUM_MAS);
-       DECLARE_BITMAP(pending, UWB_NUM_MAS);
-       struct uwb_ie_drp_avail ie;
-       bool ie_valid;
-};
-
-struct uwb_drp_backoff_win {
-       u8 window;
-       u8 n;
-       int total_expired;
-       struct timer_list timer;
-       bool can_reserve_extra_mases;
-};
-
-const char *uwb_rsv_state_str(enum uwb_rsv_state state);
-const char *uwb_rsv_type_str(enum uwb_drp_type type);
-
-struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb,
-                              void *pal_priv);
-void uwb_rsv_destroy(struct uwb_rsv *rsv);
-
-int uwb_rsv_establish(struct uwb_rsv *rsv);
-int uwb_rsv_modify(struct uwb_rsv *rsv,
-                  int max_mas, int min_mas, int sparsity);
-void uwb_rsv_terminate(struct uwb_rsv *rsv);
-
-void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv);
-
-void uwb_rsv_get_usable_mas(struct uwb_rsv *orig_rsv, struct uwb_mas_bm *mas);
-
-/**
- * Radio Control Interface instance
- *
- *
- * Life cycle rules: those of the UWB Device.
- *
- * @index:    an index number for this radio controller, as used in the
- *            device name.
- * @version:  version of protocol supported by this device
- * @priv:     Backend implementation; rw with uwb_dev.dev.sem taken.
- * @cmd:      Backend implementation to execute commands; rw and call
- *            only  with uwb_dev.dev.sem taken.
- * @reset:    Hardware reset of radio controller and any PAL controllers.
- * @filter:   Backend implementation to manipulate data to and from device
- *            to be compliant to specification assumed by driver (WHCI
- *            0.95).
- *
- *            uwb_dev.dev.mutex is used to execute commands and update
- *            the corresponding structures; can't use a spinlock
- *            because rc->cmd() can sleep.
- * @ies:         This is a dynamically allocated array cacheing the
- *               IEs (settable by the host) that the beacon of this
- *               radio controller is currently sending.
- *
- *               In reality, we store here the full command we set to
- *               the radio controller (which is basically a command
- *               prefix followed by all the IEs the beacon currently
- *               contains). This way we don't have to realloc and
- *               memcpy when setting it.
- *
- *               We set this up in uwb_rc_ie_setup(), where we alloc
- *               this struct, call get_ie() [so we know which IEs are
- *               currently being sent, if any].
- *
- * @ies_capacity:Amount of space (in bytes) allocated in @ies. The
- *               amount used is given by sizeof(*ies) plus ies->wIELength
- *               (which is a little endian quantity all the time).
- * @ies_mutex:   protect the IE cache
- * @dbg:         information for the debug interface
- */
-struct uwb_rc {
-       struct uwb_dev uwb_dev;
-       int index;
-       u16 version;
-
-       struct module *owner;
-       void *priv;
-       int (*start)(struct uwb_rc *rc);
-       void (*stop)(struct uwb_rc *rc);
-       int (*cmd)(struct uwb_rc *, const struct uwb_rccb *, size_t);
-       int (*reset)(struct uwb_rc *rc);
-       int (*filter_cmd)(struct uwb_rc *, struct uwb_rccb **, size_t *);
-       int (*filter_event)(struct uwb_rc *, struct uwb_rceb **, const size_t,
-                           size_t *, size_t *);
-
-       spinlock_t neh_lock;            /* protects neh_* and ctx_* */
-       struct list_head neh_list;      /* Open NE handles */
-       unsigned long ctx_bm[UWB_RC_CTX_MAX / 8 / sizeof(unsigned long)];
-       u8 ctx_roll;
-
-       int beaconing;                  /* Beaconing state [channel number] */
-       int beaconing_forced;
-       int scanning;
-       enum uwb_scan_type scan_type:3;
-       unsigned ready:1;
-       struct uwb_notifs_chain notifs_chain;
-       struct uwb_beca uwb_beca;
-
-       struct uwbd uwbd;
-
-       struct uwb_drp_backoff_win bow;
-       struct uwb_drp_avail drp_avail;
-       struct list_head reservations;
-       struct list_head cnflt_alien_list;
-       struct uwb_mas_bm cnflt_alien_bitmap;
-       struct mutex rsvs_mutex;
-       spinlock_t rsvs_lock;
-       struct workqueue_struct *rsv_workq;
-
-       struct delayed_work rsv_update_work;
-       struct delayed_work rsv_alien_bp_work;
-       int set_drp_ie_pending;
-       struct mutex ies_mutex;
-       struct uwb_rc_cmd_set_ie *ies;
-       size_t ies_capacity;
-
-       struct list_head pals;
-       int active_pals;
-
-       struct uwb_dbg *dbg;
-};
-
-
-/**
- * struct uwb_pal - a UWB PAL
- * @name:    descriptive name for this PAL (wusbhc, wlp, etc.).
- * @device:  a device for the PAL.  Used to link the PAL and the radio
- *           controller in sysfs.
- * @rc:      the radio controller the PAL uses.
- * @channel_changed: called when the channel used by the radio changes.
- *           A channel of -1 means the channel has been stopped.
- * @new_rsv: called when a peer requests a reservation (may be NULL if
- *           the PAL cannot accept reservation requests).
- * @channel: channel being used by the PAL; 0 if the PAL isn't using
- *           the radio; -1 if the PAL wishes to use the radio but
- *           cannot.
- * @debugfs_dir: a debugfs directory which the PAL can use for its own
- *           debugfs files.
- *
- * A Protocol Adaptation Layer (PAL) is a user of the WiMedia UWB
- * radio platform (e.g., WUSB, WLP or Bluetooth UWB AMP).
- *
- * The PALs using a radio controller must register themselves to
- * permit the UWB stack to coordinate usage of the radio between the
- * various PALs or to allow PALs to response to certain requests from
- * peers.
- *
- * A struct uwb_pal should be embedded in a containing structure
- * belonging to the PAL and initialized with uwb_pal_init()).  Fields
- * should be set appropriately by the PAL before registering the PAL
- * with uwb_pal_register().
- */
-struct uwb_pal {
-       struct list_head node;
-       const char *name;
-       struct device *device;
-       struct uwb_rc *rc;
-
-       void (*channel_changed)(struct uwb_pal *pal, int channel);
-       void (*new_rsv)(struct uwb_pal *pal, struct uwb_rsv *rsv);
-
-       int channel;
-       struct dentry *debugfs_dir;
-};
-
-void uwb_pal_init(struct uwb_pal *pal);
-int uwb_pal_register(struct uwb_pal *pal);
-void uwb_pal_unregister(struct uwb_pal *pal);
-
-int uwb_radio_start(struct uwb_pal *pal);
-void uwb_radio_stop(struct uwb_pal *pal);
-
-/*
- * General public API
- *
- * This API can be used by UWB device drivers or by those implementing
- * UWB Radio Controllers
- */
-struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc,
-                                      const struct uwb_dev_addr *devaddr);
-struct uwb_dev *uwb_dev_get_by_rc(struct uwb_dev *, struct uwb_rc *);
-static inline void uwb_dev_get(struct uwb_dev *uwb_dev)
-{
-       get_device(&uwb_dev->dev);
-}
-static inline void uwb_dev_put(struct uwb_dev *uwb_dev)
-{
-       put_device(&uwb_dev->dev);
-}
-struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev);
-
-/**
- * Callback function for 'uwb_{dev,rc}_foreach()'.
- *
- * @dev:  Linux device instance
- *        'uwb_dev = container_of(dev, struct uwb_dev, dev)'
- * @priv: Data passed by the caller to 'uwb_{dev,rc}_foreach()'.
- *
- * @returns: 0 to continue the iterations, any other val to stop
- *           iterating and return the value to the caller of
- *           _foreach().
- */
-typedef int (*uwb_dev_for_each_f)(struct device *dev, void *priv);
-int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f func, void *priv);
-
-struct uwb_rc *uwb_rc_alloc(void);
-struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *);
-struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *);
-void uwb_rc_put(struct uwb_rc *rc);
-
-typedef void (*uwb_rc_cmd_cb_f)(struct uwb_rc *rc, void *arg,
-                                struct uwb_rceb *reply, ssize_t reply_size);
-
-int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name,
-                    struct uwb_rccb *cmd, size_t cmd_size,
-                    u8 expected_type, u16 expected_event,
-                    uwb_rc_cmd_cb_f cb, void *arg);
-ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name,
-                  struct uwb_rccb *cmd, size_t cmd_size,
-                  struct uwb_rceb *reply, size_t reply_size);
-ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name,
-                   struct uwb_rccb *cmd, size_t cmd_size,
-                   u8 expected_type, u16 expected_event,
-                   struct uwb_rceb **preply);
-
-size_t __uwb_addr_print(char *, size_t, const unsigned char *, int);
-
-int uwb_rc_dev_addr_set(struct uwb_rc *, const struct uwb_dev_addr *);
-int uwb_rc_dev_addr_get(struct uwb_rc *, struct uwb_dev_addr *);
-int uwb_rc_mac_addr_set(struct uwb_rc *, const struct uwb_mac_addr *);
-int uwb_rc_mac_addr_get(struct uwb_rc *, struct uwb_mac_addr *);
-int __uwb_mac_addr_assigned_check(struct device *, void *);
-int __uwb_dev_addr_assigned_check(struct device *, void *);
-
-/* Print in @buf a pretty repr of @addr */
-static inline size_t uwb_dev_addr_print(char *buf, size_t buf_size,
-                                       const struct uwb_dev_addr *addr)
-{
-       return __uwb_addr_print(buf, buf_size, addr->data, 0);
-}
-
-/* Print in @buf a pretty repr of @addr */
-static inline size_t uwb_mac_addr_print(char *buf, size_t buf_size,
-                                       const struct uwb_mac_addr *addr)
-{
-       return __uwb_addr_print(buf, buf_size, addr->data, 1);
-}
-
-/* @returns 0 if device addresses @addr2 and @addr1 are equal */
-static inline int uwb_dev_addr_cmp(const struct uwb_dev_addr *addr1,
-                                  const struct uwb_dev_addr *addr2)
-{
-       return memcmp(addr1, addr2, sizeof(*addr1));
-}
-
-/* @returns 0 if MAC addresses @addr2 and @addr1 are equal */
-static inline int uwb_mac_addr_cmp(const struct uwb_mac_addr *addr1,
-                                  const struct uwb_mac_addr *addr2)
-{
-       return memcmp(addr1, addr2, sizeof(*addr1));
-}
-
-/* @returns !0 if a MAC @addr is a broadcast address */
-static inline int uwb_mac_addr_bcast(const struct uwb_mac_addr *addr)
-{
-       struct uwb_mac_addr bcast = {
-               .data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
-       };
-       return !uwb_mac_addr_cmp(addr, &bcast);
-}
-
-/* @returns !0 if a MAC @addr is all zeroes*/
-static inline int uwb_mac_addr_unset(const struct uwb_mac_addr *addr)
-{
-       struct uwb_mac_addr unset = {
-               .data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
-       };
-       return !uwb_mac_addr_cmp(addr, &unset);
-}
-
-/* @returns !0 if the address is in use. */
-static inline unsigned __uwb_dev_addr_assigned(struct uwb_rc *rc,
-                                              struct uwb_dev_addr *addr)
-{
-       return uwb_dev_for_each(rc, __uwb_dev_addr_assigned_check, addr);
-}
-
-/*
- * UWB Radio Controller API
- *
- * This API is used (in addition to the general API) to implement UWB
- * Radio Controllers.
- */
-void uwb_rc_init(struct uwb_rc *);
-int uwb_rc_add(struct uwb_rc *, struct device *dev, void *rc_priv);
-void uwb_rc_rm(struct uwb_rc *);
-void uwb_rc_neh_grok(struct uwb_rc *, void *, size_t);
-void uwb_rc_neh_error(struct uwb_rc *, int);
-void uwb_rc_reset_all(struct uwb_rc *rc);
-void uwb_rc_pre_reset(struct uwb_rc *rc);
-int uwb_rc_post_reset(struct uwb_rc *rc);
-
-/**
- * uwb_rsv_is_owner - is the owner of this reservation the RC?
- * @rsv: the reservation
- */
-static inline bool uwb_rsv_is_owner(struct uwb_rsv *rsv)
-{
-       return rsv->owner == &rsv->rc->uwb_dev;
-}
-
-/**
- * enum uwb_notifs - UWB events that can be passed to any listeners
- * @UWB_NOTIF_ONAIR: a new neighbour has joined the beacon group.
- * @UWB_NOTIF_OFFAIR: a neighbour has left the beacon group.
- *
- * Higher layers can register callback functions with the radio
- * controller using uwb_notifs_register(). The radio controller
- * maintains a list of all registered handlers and will notify all
- * nodes when an event occurs.
- */
-enum uwb_notifs {
-       UWB_NOTIF_ONAIR,
-       UWB_NOTIF_OFFAIR,
-};
-
-/* Callback function registered with UWB */
-struct uwb_notifs_handler {
-       struct list_head list_node;
-       void (*cb)(void *, struct uwb_dev *, enum uwb_notifs);
-       void *data;
-};
-
-int uwb_notifs_register(struct uwb_rc *, struct uwb_notifs_handler *);
-int uwb_notifs_deregister(struct uwb_rc *, struct uwb_notifs_handler *);
-
-
-/**
- * UWB radio controller Event Size Entry (for creating entry tables)
- *
- * WUSB and WHCI define events and notifications, and they might have
- * fixed or variable size.
- *
- * Each event/notification has a size which is not necessarily known
- * in advance based on the event code. As well, vendor specific
- * events/notifications will have a size impossible to determine
- * unless we know about the device's specific details.
- *
- * It was way too smart of the spec writers not to think that it would
- * be impossible for a generic driver to skip over vendor specific
- * events/notifications if there are no LENGTH fields in the HEADER of
- * each message...the transaction size cannot be counted on as the
- * spec does not forbid to pack more than one event in a single
- * transaction.
- *
- * Thus, we guess sizes with tables (or for events, when you know the
- * size ahead of time you can use uwb_rc_neh_extra_size*()). We
- * register tables with the known events and their sizes, and then we
- * traverse those tables. For those with variable length, we provide a
- * way to lookup the size inside the event/notification's
- * payload. This allows device-specific event size tables to be
- * registered.
- *
- * @size:   Size of the payload
- *
- * @offset: if != 0, at offset @offset-1 starts a field with a length
- *          that has to be added to @size. The format of the field is
- *          given by @type.
- *
- * @type:   Type and length of the offset field. Most common is LE 16
- *          bits (that's why that is zero); others are there mostly to
- *          cover for bugs and weirdos.
- */
-struct uwb_est_entry {
-       size_t size;
-       unsigned offset;
-       enum { UWB_EST_16 = 0, UWB_EST_8 = 1 } type;
-};
-
-int uwb_est_register(u8 type, u8 code_high, u16 vendor, u16 product,
-                    const struct uwb_est_entry *, size_t entries);
-int uwb_est_unregister(u8 type, u8 code_high, u16 vendor, u16 product,
-                      const struct uwb_est_entry *, size_t entries);
-ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb,
-                         size_t len);
-
-/* -- Misc */
-
-enum {
-       EDC_MAX_ERRORS = 10,
-       EDC_ERROR_TIMEFRAME = HZ,
-};
-
-/* error density counter */
-struct edc {
-       unsigned long timestart;
-       u16 errorcount;
-};
-
-static inline
-void edc_init(struct edc *edc)
-{
-       edc->timestart = jiffies;
-}
-
-/* Called when an error occurred.
- * This is way to determine if the number of acceptable errors per time
- * period has been exceeded. It is not accurate as there are cases in which
- * this scheme will not work, for example if there are periodic occurrences
- * of errors that straddle updates to the start time. This scheme is
- * sufficient for our usage.
- *
- * @returns 1 if maximum acceptable errors per timeframe has been exceeded.
- */
-static inline int edc_inc(struct edc *err_hist, u16 max_err, u16 timeframe)
-{
-       unsigned long now;
-
-       now = jiffies;
-       if (now - err_hist->timestart > timeframe) {
-               err_hist->errorcount = 1;
-               err_hist->timestart = now;
-       } else if (++err_hist->errorcount > max_err) {
-                       err_hist->errorcount = 0;
-                       err_hist->timestart = now;
-                       return 1;
-       }
-       return 0;
-}
-
-
-/* Information Element handling */
-
-struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len);
-int uwb_rc_ie_add(struct uwb_rc *uwb_rc, const struct uwb_ie_hdr *ies, size_t size);
-int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id);
-
-/*
- * Transmission statistics
- *
- * UWB uses LQI and RSSI (one byte values) for reporting radio signal
- * strength and line quality indication. We do quick and dirty
- * averages of those. They are signed values, btw.
- *
- * For 8 bit quantities, we keep the min, the max, an accumulator
- * (@sigma) and a # of samples. When @samples gets to 255, we compute
- * the average (@sigma / @samples), place it in @sigma and reset
- * @samples to 1 (so we use it as the first sample).
- *
- * Now, statistically speaking, probably I am kicking the kidneys of
- * some books I have in my shelves collecting dust, but I just want to
- * get an approx, not the Nobel.
- *
- * LOCKING: there is no locking per se, but we try to keep a lockless
- * schema. Only _add_samples() modifies the values--as long as you
- * have other locking on top that makes sure that no two calls of
- * _add_sample() happen at the same time, then we are fine. Now, for
- * resetting the values we just set @samples to 0 and that makes the
- * next _add_sample() to start with defaults. Reading the values in
- * _show() currently can race, so you need to make sure the calls are
- * under the same lock that protects calls to _add_sample(). FIXME:
- * currently unlocked (It is not ultraprecise but does the trick. Bite
- * me).
- */
-struct stats {
-       s8 min, max;
-       s16 sigma;
-       atomic_t samples;
-};
-
-static inline
-void stats_init(struct stats *stats)
-{
-       atomic_set(&stats->samples, 0);
-       wmb();
-}
-
-static inline
-void stats_add_sample(struct stats *stats, s8 sample)
-{
-       s8 min, max;
-       s16 sigma;
-       unsigned samples = atomic_read(&stats->samples);
-       if (samples == 0) {     /* it was zero before, so we initialize */
-               min = 127;
-               max = -128;
-               sigma = 0;
-       } else {
-               min = stats->min;
-               max = stats->max;
-               sigma = stats->sigma;
-       }
-
-       if (sample < min)       /* compute new values */
-               min = sample;
-       else if (sample > max)
-               max = sample;
-       sigma += sample;
-
-       stats->min = min;       /* commit */
-       stats->max = max;
-       stats->sigma = sigma;
-       if (atomic_add_return(1, &stats->samples) > 255) {
-               /* wrapped around! reset */
-               stats->sigma = sigma / 256;
-               atomic_set(&stats->samples, 1);
-       }
-}
-
-static inline ssize_t stats_show(struct stats *stats, char *buf)
-{
-       int min, max, avg;
-       int samples = atomic_read(&stats->samples);
-       if (samples == 0)
-               min = max = avg = 0;
-       else {
-               min = stats->min;
-               max = stats->max;
-               avg = stats->sigma / samples;
-       }
-       return scnprintf(buf, PAGE_SIZE, "%d %d %d\n", min, max, avg);
-}
-
-static inline ssize_t stats_store(struct stats *stats, const char *buf,
-                                 size_t size)
-{
-       stats_init(stats);
-       return size;
-}
-
-#endif /* #ifndef __LINUX__UWB_H__ */
diff --git a/include/linux/uwb/debug-cmd.h b/include/linux/uwb/debug-cmd.h
deleted file mode 100644 (file)
index f97db6c..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Ultra Wide Band
- * Debug interface commands
- *
- * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
- */
-#ifndef __LINUX__UWB__DEBUG_CMD_H__
-#define __LINUX__UWB__DEBUG_CMD_H__
-
-#include <linux/types.h>
-
-/*
- * Debug interface commands
- *
- * UWB_DBG_CMD_RSV_ESTABLISH: Establish a new unicast reservation.
- *
- * UWB_DBG_CMD_RSV_TERMINATE: Terminate the Nth reservation.
- */
-
-enum uwb_dbg_cmd_type {
-       UWB_DBG_CMD_RSV_ESTABLISH = 1,
-       UWB_DBG_CMD_RSV_TERMINATE = 2,
-       UWB_DBG_CMD_IE_ADD = 3,
-       UWB_DBG_CMD_IE_RM = 4,
-       UWB_DBG_CMD_RADIO_START = 5,
-       UWB_DBG_CMD_RADIO_STOP = 6,
-};
-
-struct uwb_dbg_cmd_rsv_establish {
-       __u8  target[6];
-       __u8  type;
-       __u16 max_mas;
-       __u16 min_mas;
-       __u8  max_interval;
-};
-
-struct uwb_dbg_cmd_rsv_terminate {
-       int index;
-};
-
-struct uwb_dbg_cmd_ie {
-       __u8 data[128];
-       int len;
-};
-
-struct uwb_dbg_cmd {
-       __u32 type;
-       union {
-               struct uwb_dbg_cmd_rsv_establish rsv_establish;
-               struct uwb_dbg_cmd_rsv_terminate rsv_terminate;
-               struct uwb_dbg_cmd_ie ie_add;
-               struct uwb_dbg_cmd_ie ie_rm;
-       };
-};
-
-#endif /* #ifndef __LINUX__UWB__DEBUG_CMD_H__ */
diff --git a/include/linux/uwb/spec.h b/include/linux/uwb/spec.h
deleted file mode 100644 (file)
index 5f75caf..0000000
+++ /dev/null
@@ -1,767 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Ultra Wide Band
- * UWB Standard definitions
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * All these definitions are based on the ECMA-368 standard.
- *
- * Note all definitions are Little Endian in the wire, and we will
- * convert them to host order before operating on the bitfields (that
- * yes, we use extensively).
- */
-
-#ifndef __LINUX__UWB_SPEC_H__
-#define __LINUX__UWB_SPEC_H__
-
-#include <linux/types.h>
-#include <linux/bitmap.h>
-#include <linux/if_ether.h>
-
-#define i1480_FW 0x00000303
-/* #define i1480_FW 0x00000302 */
-
-/**
- * Number of Medium Access Slots in a superframe.
- *
- * UWB divides time in SuperFrames, each one divided in 256 pieces, or
- * Medium Access Slots. See MBOA MAC[5.4.5] for details. The MAS is the
- * basic bandwidth allocation unit in UWB.
- */
-enum { UWB_NUM_MAS = 256 };
-
-/**
- * Number of Zones in superframe.
- *
- * UWB divides the superframe into zones with numbering starting from BPST.
- * See MBOA MAC[16.8.6]
- */
-enum { UWB_NUM_ZONES = 16 };
-
-/*
- * Number of MAS in a zone.
- */
-#define UWB_MAS_PER_ZONE (UWB_NUM_MAS / UWB_NUM_ZONES)
-
-/*
- * Number of MAS required before a row can be considered available.
- */
-#define UWB_USABLE_MAS_PER_ROW (UWB_NUM_ZONES - 1)
-
-/*
- * Number of streams per DRP reservation between a pair of devices.
- *
- * [ECMA-368] section 16.8.6.
- */
-enum { UWB_NUM_STREAMS = 8 };
-
-/*
- * mMasLength
- *
- * The length of a MAS in microseconds.
- *
- * [ECMA-368] section 17.16.
- */
-enum { UWB_MAS_LENGTH_US = 256 };
-
-/*
- * mBeaconSlotLength
- *
- * The length of the beacon slot in microseconds.
- *
- * [ECMA-368] section 17.16
- */
-enum { UWB_BEACON_SLOT_LENGTH_US = 85 };
-
-/*
- * mMaxLostBeacons
- *
- * The number beacons missing in consecutive superframes before a
- * device can be considered as unreachable.
- *
- * [ECMA-368] section 17.16
- */
-enum { UWB_MAX_LOST_BEACONS = 3 };
-
-/*
- * mDRPBackOffWinMin
- *
- * The minimum number of superframes to wait before trying to reserve
- * extra MAS.
- *
- * [ECMA-368] section 17.16
- */
-enum { UWB_DRP_BACKOFF_WIN_MIN = 2 };
-
-/*
- * mDRPBackOffWinMax
- *
- * The maximum number of superframes to wait before trying to reserve
- * extra MAS.
- *
- * [ECMA-368] section 17.16
- */
-enum { UWB_DRP_BACKOFF_WIN_MAX = 16 };
-
-/*
- * Length of a superframe in microseconds.
- */
-#define UWB_SUPERFRAME_LENGTH_US (UWB_MAS_LENGTH_US * UWB_NUM_MAS)
-
-/**
- * UWB MAC address
- *
- * It is *imperative* that this struct is exactly 6 packed bytes (as
- * it is also used to define headers sent down and up the wire/radio).
- */
-struct uwb_mac_addr {
-       u8 data[ETH_ALEN];
-} __attribute__((packed));
-
-
-/**
- * UWB device address
- *
- * It is *imperative* that this struct is exactly 6 packed bytes (as
- * it is also used to define headers sent down and up the wire/radio).
- */
-struct uwb_dev_addr {
-       u8 data[2];
-} __attribute__((packed));
-
-
-/**
- * Types of UWB addresses
- *
- * Order matters (by size).
- */
-enum uwb_addr_type {
-       UWB_ADDR_DEV = 0,
-       UWB_ADDR_MAC = 1,
-};
-
-
-/** Size of a char buffer for printing a MAC/device address */
-enum { UWB_ADDR_STRSIZE = 32 };
-
-
-/** UWB WiMedia protocol IDs. */
-enum uwb_prid {
-       UWB_PRID_WLP_RESERVED   = 0x0000,
-       UWB_PRID_WLP            = 0x0001,
-       UWB_PRID_WUSB_BOT       = 0x0010,
-       UWB_PRID_WUSB           = 0x0010,
-       UWB_PRID_WUSB_TOP       = 0x001F,
-};
-
-
-/** PHY Rate (MBOA MAC[7.8.12, Table 61]) */
-enum uwb_phy_rate {
-       UWB_PHY_RATE_53 = 0,
-       UWB_PHY_RATE_80,
-       UWB_PHY_RATE_106,
-       UWB_PHY_RATE_160,
-       UWB_PHY_RATE_200,
-       UWB_PHY_RATE_320,
-       UWB_PHY_RATE_400,
-       UWB_PHY_RATE_480,
-       UWB_PHY_RATE_INVALID
-};
-
-
-/**
- * Different ways to scan (MBOA MAC[6.2.2, Table 8], WUSB[Table 8-78])
- */
-enum uwb_scan_type {
-       UWB_SCAN_ONLY = 0,
-       UWB_SCAN_OUTSIDE_BP,
-       UWB_SCAN_WHILE_INACTIVE,
-       UWB_SCAN_DISABLED,
-       UWB_SCAN_ONLY_STARTTIME,
-       UWB_SCAN_TOP
-};
-
-
-/** ACK Policy types (MBOA MAC[7.2.1.3]) */
-enum uwb_ack_pol {
-       UWB_ACK_NO = 0,
-       UWB_ACK_INM = 1,
-       UWB_ACK_B = 2,
-       UWB_ACK_B_REQ = 3,
-};
-
-
-/** DRP reservation types ([ECMA-368 table 106) */
-enum uwb_drp_type {
-       UWB_DRP_TYPE_ALIEN_BP = 0,
-       UWB_DRP_TYPE_HARD,
-       UWB_DRP_TYPE_SOFT,
-       UWB_DRP_TYPE_PRIVATE,
-       UWB_DRP_TYPE_PCA,
-};
-
-
-/** DRP Reason Codes ([ECMA-368] table 107) */
-enum uwb_drp_reason {
-       UWB_DRP_REASON_ACCEPTED = 0,
-       UWB_DRP_REASON_CONFLICT,
-       UWB_DRP_REASON_PENDING,
-       UWB_DRP_REASON_DENIED,
-       UWB_DRP_REASON_MODIFIED,
-};
-
-/** Relinquish Request Reason Codes ([ECMA-368] table 113) */
-enum uwb_relinquish_req_reason {
-       UWB_RELINQUISH_REQ_REASON_NON_SPECIFIC = 0,
-       UWB_RELINQUISH_REQ_REASON_OVER_ALLOCATION,
-};
-
-/**
- *  DRP Notification Reason Codes (WHCI 0.95 [3.1.4.9])
- */
-enum uwb_drp_notif_reason {
-       UWB_DRP_NOTIF_DRP_IE_RCVD = 0,
-       UWB_DRP_NOTIF_CONFLICT,
-       UWB_DRP_NOTIF_TERMINATE,
-};
-
-
-/** Allocation of MAS slots in a DRP request MBOA MAC[7.8.7] */
-struct uwb_drp_alloc {
-       __le16 zone_bm;
-       __le16 mas_bm;
-} __attribute__((packed));
-
-
-/** General MAC Header format (ECMA-368[16.2]) */
-struct uwb_mac_frame_hdr {
-       __le16 Frame_Control;
-       struct uwb_dev_addr DestAddr;
-       struct uwb_dev_addr SrcAddr;
-       __le16 Sequence_Control;
-       __le16 Access_Information;
-} __attribute__((packed));
-
-
-/**
- * uwb_beacon_frame - a beacon frame including MAC headers
- *
- * [ECMA] section 16.3.
- */
-struct uwb_beacon_frame {
-       struct uwb_mac_frame_hdr hdr;
-       struct uwb_mac_addr Device_Identifier;  /* may be a NULL EUI-48 */
-       u8 Beacon_Slot_Number;
-       u8 Device_Control;
-       u8 IEData[];
-} __attribute__((packed));
-
-
-/** Information Element codes (MBOA MAC[T54]) */
-enum uwb_ie {
-       UWB_PCA_AVAILABILITY = 2,
-       UWB_IE_DRP_AVAILABILITY = 8,
-       UWB_IE_DRP = 9,
-       UWB_BP_SWITCH_IE = 11,
-       UWB_MAC_CAPABILITIES_IE = 12,
-       UWB_PHY_CAPABILITIES_IE = 13,
-       UWB_APP_SPEC_PROBE_IE = 15,
-       UWB_IDENTIFICATION_IE = 19,
-       UWB_MASTER_KEY_ID_IE = 20,
-       UWB_RELINQUISH_REQUEST_IE = 21,
-       UWB_IE_WLP = 250, /* WiMedia Logical Link Control Protocol WLP 0.99 */
-       UWB_APP_SPEC_IE = 255,
-};
-
-
-/**
- * Header common to all Information Elements (IEs)
- */
-struct uwb_ie_hdr {
-       u8 element_id;  /* enum uwb_ie */
-       u8 length;
-} __attribute__((packed));
-
-
-/** Dynamic Reservation Protocol IE (MBOA MAC[7.8.6]) */
-struct uwb_ie_drp {
-       struct uwb_ie_hdr       hdr;
-       __le16                  drp_control;
-       struct uwb_dev_addr     dev_addr;
-       struct uwb_drp_alloc    allocs[];
-} __attribute__((packed));
-
-static inline int uwb_ie_drp_type(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 0) & 0x7;
-}
-
-static inline int uwb_ie_drp_stream_index(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 3) & 0x7;
-}
-
-static inline int uwb_ie_drp_reason_code(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 6) & 0x7;
-}
-
-static inline int uwb_ie_drp_status(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 9) & 0x1;
-}
-
-static inline int uwb_ie_drp_owner(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 10) & 0x1;
-}
-
-static inline int uwb_ie_drp_tiebreaker(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 11) & 0x1;
-}
-
-static inline int uwb_ie_drp_unsafe(struct uwb_ie_drp *ie)
-{
-       return (le16_to_cpu(ie->drp_control) >> 12) & 0x1;
-}
-
-static inline void uwb_ie_drp_set_type(struct uwb_ie_drp *ie, enum uwb_drp_type type)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x7 << 0)) | (type << 0);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_stream_index(struct uwb_ie_drp *ie, int stream_index)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x7 << 3)) | (stream_index << 3);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_reason_code(struct uwb_ie_drp *ie,
-                                      enum uwb_drp_reason reason_code)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (ie->drp_control & ~(0x7 << 6)) | (reason_code << 6);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_status(struct uwb_ie_drp *ie, int status)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x1 << 9)) | (status << 9);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_owner(struct uwb_ie_drp *ie, int owner)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x1 << 10)) | (owner << 10);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_tiebreaker(struct uwb_ie_drp *ie, int tiebreaker)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x1 << 11)) | (tiebreaker << 11);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-static inline void uwb_ie_drp_set_unsafe(struct uwb_ie_drp *ie, int unsafe)
-{
-       u16 drp_control = le16_to_cpu(ie->drp_control);
-       drp_control = (drp_control & ~(0x1 << 12)) | (unsafe << 12);
-       ie->drp_control = cpu_to_le16(drp_control);
-}
-
-/** Dynamic Reservation Protocol IE (MBOA MAC[7.8.7]) */
-struct uwb_ie_drp_avail {
-       struct uwb_ie_hdr       hdr;
-       DECLARE_BITMAP(bmp, UWB_NUM_MAS);
-} __attribute__((packed));
-
-/* Relinqish Request IE ([ECMA-368] section 16.8.19). */
-struct uwb_relinquish_request_ie {
-        struct uwb_ie_hdr       hdr;
-        __le16                  relinquish_req_control;
-        struct uwb_dev_addr     dev_addr;
-        struct uwb_drp_alloc    allocs[];
-} __attribute__((packed));
-
-static inline int uwb_ie_relinquish_req_reason_code(struct uwb_relinquish_request_ie *ie)
-{
-       return (le16_to_cpu(ie->relinquish_req_control) >> 0) & 0xf;
-}
-
-static inline void uwb_ie_relinquish_req_set_reason_code(struct uwb_relinquish_request_ie *ie,
-                                                        int reason_code)
-{
-       u16 ctrl = le16_to_cpu(ie->relinquish_req_control);
-       ctrl = (ctrl & ~(0xf << 0)) | (reason_code << 0);
-       ie->relinquish_req_control = cpu_to_le16(ctrl);
-}
-
-/**
- * The Vendor ID is set to an OUI that indicates the vendor of the device.
- * ECMA-368 [16.8.10]
- */
-struct uwb_vendor_id {
-       u8 data[3];
-} __attribute__((packed));
-
-/**
- * The device type ID
- * FIXME: clarify what this means
- * ECMA-368 [16.8.10]
- */
-struct uwb_device_type_id {
-       u8 data[3];
-} __attribute__((packed));
-
-
-/**
- * UWB device information types
- * ECMA-368 [16.8.10]
- */
-enum uwb_dev_info_type {
-       UWB_DEV_INFO_VENDOR_ID = 0,
-       UWB_DEV_INFO_VENDOR_TYPE,
-       UWB_DEV_INFO_NAME,
-};
-
-/**
- * UWB device information found in Identification IE
- * ECMA-368 [16.8.10]
- */
-struct uwb_dev_info {
-       u8 type;        /* enum uwb_dev_info_type */
-       u8 length;
-       u8 data[];
-} __attribute__((packed));
-
-/**
- * UWB Identification IE
- * ECMA-368 [16.8.10]
- */
-struct uwb_identification_ie {
-       struct uwb_ie_hdr hdr;
-       struct uwb_dev_info info[];
-} __attribute__((packed));
-
-/*
- * UWB Radio Controller
- *
- * These definitions are common to the Radio Control layers as
- * exported by the WUSB1.0 HWA and WHCI interfaces.
- */
-
-/** Radio Control Command Block (WUSB1.0[Table 8-65] and WHCI 0.95) */
-struct uwb_rccb {
-       u8 bCommandType;                /* enum hwa_cet */
-       __le16 wCommand;                /* Command code */
-       u8 bCommandContext;             /* Context ID */
-} __attribute__((packed));
-
-
-/** Radio Control Event Block (WUSB[table 8-66], WHCI 0.95) */
-struct uwb_rceb {
-       u8 bEventType;                  /* enum hwa_cet */
-       __le16 wEvent;                  /* Event code */
-       u8 bEventContext;               /* Context ID */
-} __attribute__((packed));
-
-
-enum {
-       UWB_RC_CET_GENERAL = 0,         /* General Command/Event type */
-       UWB_RC_CET_EX_TYPE_1 = 1,       /* Extended Type 1 Command/Event type */
-};
-
-/* Commands to the radio controller */
-enum uwb_rc_cmd {
-       UWB_RC_CMD_CHANNEL_CHANGE = 16,
-       UWB_RC_CMD_DEV_ADDR_MGMT = 17,  /* Device Address Management */
-       UWB_RC_CMD_GET_IE = 18,         /* GET Information Elements */
-       UWB_RC_CMD_RESET = 19,
-       UWB_RC_CMD_SCAN = 20,           /* Scan management  */
-       UWB_RC_CMD_SET_BEACON_FILTER = 21,
-       UWB_RC_CMD_SET_DRP_IE = 22,     /* Dynamic Reservation Protocol IEs */
-       UWB_RC_CMD_SET_IE = 23,         /* Information Element management */
-       UWB_RC_CMD_SET_NOTIFICATION_FILTER = 24,
-       UWB_RC_CMD_SET_TX_POWER = 25,
-       UWB_RC_CMD_SLEEP = 26,
-       UWB_RC_CMD_START_BEACON = 27,
-       UWB_RC_CMD_STOP_BEACON = 28,
-       UWB_RC_CMD_BP_MERGE = 29,
-       UWB_RC_CMD_SEND_COMMAND_FRAME = 30,
-       UWB_RC_CMD_SET_ASIE_NOTIF = 31,
-};
-
-/* Notifications from the radio controller */
-enum uwb_rc_evt {
-       UWB_RC_EVT_IE_RCV = 0,
-       UWB_RC_EVT_BEACON = 1,
-       UWB_RC_EVT_BEACON_SIZE = 2,
-       UWB_RC_EVT_BPOIE_CHANGE = 3,
-       UWB_RC_EVT_BP_SLOT_CHANGE = 4,
-       UWB_RC_EVT_BP_SWITCH_IE_RCV = 5,
-       UWB_RC_EVT_DEV_ADDR_CONFLICT = 6,
-       UWB_RC_EVT_DRP_AVAIL = 7,
-       UWB_RC_EVT_DRP = 8,
-       UWB_RC_EVT_BP_SWITCH_STATUS = 9,
-       UWB_RC_EVT_CMD_FRAME_RCV = 10,
-       UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV = 11,
-       /* Events (command responses) use the same code as the command */
-       UWB_RC_EVT_UNKNOWN_CMD_RCV = 65535,
-};
-
-enum uwb_rc_extended_type_1_cmd {
-       UWB_RC_SET_DAA_ENERGY_MASK = 32,
-       UWB_RC_SET_NOTIFICATION_FILTER_EX = 33,
-};
-
-enum uwb_rc_extended_type_1_evt {
-       UWB_RC_DAA_ENERGY_DETECTED = 0,
-};
-
-/* Radio Control Result Code. [WHCI] table 3-3. */
-enum {
-       UWB_RC_RES_SUCCESS = 0,
-       UWB_RC_RES_FAIL,
-       UWB_RC_RES_FAIL_HARDWARE,
-       UWB_RC_RES_FAIL_NO_SLOTS,
-       UWB_RC_RES_FAIL_BEACON_TOO_LARGE,
-       UWB_RC_RES_FAIL_INVALID_PARAMETER,
-       UWB_RC_RES_FAIL_UNSUPPORTED_PWR_LEVEL,
-       UWB_RC_RES_FAIL_INVALID_IE_DATA,
-       UWB_RC_RES_FAIL_BEACON_SIZE_EXCEEDED,
-       UWB_RC_RES_FAIL_CANCELLED,
-       UWB_RC_RES_FAIL_INVALID_STATE,
-       UWB_RC_RES_FAIL_INVALID_SIZE,
-       UWB_RC_RES_FAIL_ACK_NOT_RECEIVED,
-       UWB_RC_RES_FAIL_NO_MORE_ASIE_NOTIF,
-       UWB_RC_RES_FAIL_TIME_OUT = 255,
-};
-
-/* Confirm event. [WHCI] section 3.1.3.1 etc. */
-struct uwb_rc_evt_confirm {
-       struct uwb_rceb rceb;
-       u8 bResultCode;
-} __attribute__((packed));
-
-/* Device Address Management event. [WHCI] section 3.1.3.2. */
-struct uwb_rc_evt_dev_addr_mgmt {
-       struct uwb_rceb rceb;
-       u8 baAddr[ETH_ALEN];
-       u8 bResultCode;
-} __attribute__((packed));
-
-
-/* Get IE Event. [WHCI] section 3.1.3.3. */
-struct uwb_rc_evt_get_ie {
-       struct uwb_rceb rceb;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/* Set DRP IE Event. [WHCI] section 3.1.3.7. */
-struct uwb_rc_evt_set_drp_ie {
-       struct uwb_rceb rceb;
-       __le16 wRemainingSpace;
-       u8 bResultCode;
-} __attribute__((packed));
-
-/* Set IE Event. [WHCI] section 3.1.3.8. */
-struct uwb_rc_evt_set_ie {
-       struct uwb_rceb rceb;
-       __le16 RemainingSpace;
-       u8 bResultCode;
-} __attribute__((packed));
-
-/* Scan command. [WHCI] 3.1.3.5. */
-struct uwb_rc_cmd_scan {
-       struct uwb_rccb rccb;
-       u8 bChannelNumber;
-       u8 bScanState;
-       __le16 wStartTime;
-} __attribute__((packed));
-
-/* Set DRP IE command. [WHCI] section 3.1.3.7. */
-struct uwb_rc_cmd_set_drp_ie {
-       struct uwb_rccb rccb;
-       __le16 wIELength;
-       struct uwb_ie_drp IEData[];
-} __attribute__((packed));
-
-/* Set IE command. [WHCI] section 3.1.3.8. */
-struct uwb_rc_cmd_set_ie {
-       struct uwb_rccb rccb;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/* Set DAA Energy Mask event. [WHCI 0.96] section 3.1.3.17. */
-struct uwb_rc_evt_set_daa_energy_mask {
-       struct uwb_rceb rceb;
-       __le16 wLength;
-       u8 result;
-} __attribute__((packed));
-
-/* Set Notification Filter Extended event. [WHCI 0.96] section 3.1.3.18. */
-struct uwb_rc_evt_set_notification_filter_ex {
-       struct uwb_rceb rceb;
-       __le16 wLength;
-       u8 result;
-} __attribute__((packed));
-
-/* IE Received notification. [WHCI] section 3.1.4.1. */
-struct uwb_rc_evt_ie_rcv {
-       struct uwb_rceb rceb;
-       struct uwb_dev_addr SrcAddr;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/* Type of the received beacon. [WHCI] section 3.1.4.2. */
-enum uwb_rc_beacon_type {
-       UWB_RC_BEACON_TYPE_SCAN = 0,
-       UWB_RC_BEACON_TYPE_NEIGHBOR,
-       UWB_RC_BEACON_TYPE_OL_ALIEN,
-       UWB_RC_BEACON_TYPE_NOL_ALIEN,
-};
-
-/* Beacon received notification. [WHCI] 3.1.4.2. */
-struct uwb_rc_evt_beacon {
-       struct uwb_rceb rceb;
-       u8      bChannelNumber;
-       u8      bBeaconType;
-       __le16  wBPSTOffset;
-       u8      bLQI;
-       u8      bRSSI;
-       __le16  wBeaconInfoLength;
-       u8      BeaconInfo[];
-} __attribute__((packed));
-
-
-/* Beacon Size Change notification. [WHCI] section 3.1.4.3 */
-struct uwb_rc_evt_beacon_size {
-       struct uwb_rceb rceb;
-       __le16 wNewBeaconSize;
-} __attribute__((packed));
-
-
-/* BPOIE Change notification. [WHCI] section 3.1.4.4. */
-struct uwb_rc_evt_bpoie_change {
-       struct uwb_rceb rceb;
-       __le16 wBPOIELength;
-       u8 BPOIE[];
-} __attribute__((packed));
-
-
-/* Beacon Slot Change notification. [WHCI] section 3.1.4.5. */
-struct uwb_rc_evt_bp_slot_change {
-       struct uwb_rceb rceb;
-       u8 slot_info;
-} __attribute__((packed));
-
-static inline int uwb_rc_evt_bp_slot_change_slot_num(
-       const struct uwb_rc_evt_bp_slot_change *evt)
-{
-       return evt->slot_info & 0x7f;
-}
-
-static inline int uwb_rc_evt_bp_slot_change_no_slot(
-       const struct uwb_rc_evt_bp_slot_change *evt)
-{
-       return (evt->slot_info & 0x80) >> 7;
-}
-
-/* BP Switch IE Received notification. [WHCI] section 3.1.4.6. */
-struct uwb_rc_evt_bp_switch_ie_rcv {
-       struct uwb_rceb rceb;
-       struct uwb_dev_addr wSrcAddr;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/* DevAddr Conflict notification. [WHCI] section 3.1.4.7. */
-struct uwb_rc_evt_dev_addr_conflict {
-       struct uwb_rceb rceb;
-} __attribute__((packed));
-
-/* DRP notification. [WHCI] section 3.1.4.9. */
-struct uwb_rc_evt_drp {
-       struct uwb_rceb           rceb;
-       struct uwb_dev_addr       src_addr;
-       u8                        reason;
-       u8                        beacon_slot_number;
-       __le16                    ie_length;
-       u8                        ie_data[];
-} __attribute__((packed));
-
-static inline enum uwb_drp_notif_reason uwb_rc_evt_drp_reason(struct uwb_rc_evt_drp *evt)
-{
-       return evt->reason & 0x0f;
-}
-
-
-/* DRP Availability Change notification. [WHCI] section 3.1.4.8. */
-struct uwb_rc_evt_drp_avail {
-       struct uwb_rceb rceb;
-       DECLARE_BITMAP(bmp, UWB_NUM_MAS);
-} __attribute__((packed));
-
-/* BP switch status notification. [WHCI] section 3.1.4.10. */
-struct uwb_rc_evt_bp_switch_status {
-       struct uwb_rceb rceb;
-       u8 status;
-       u8 slot_offset;
-       __le16 bpst_offset;
-       u8 move_countdown;
-} __attribute__((packed));
-
-/* Command Frame Received notification. [WHCI] section 3.1.4.11. */
-struct uwb_rc_evt_cmd_frame_rcv {
-       struct uwb_rceb rceb;
-       __le16 receive_time;
-       struct uwb_dev_addr wSrcAddr;
-       struct uwb_dev_addr wDstAddr;
-       __le16 control;
-       __le16 reserved;
-       __le16 dataLength;
-       u8 data[];
-} __attribute__((packed));
-
-/* Channel Change IE Received notification. [WHCI] section 3.1.4.12. */
-struct uwb_rc_evt_channel_change_ie_rcv {
-       struct uwb_rceb rceb;
-       struct uwb_dev_addr wSrcAddr;
-       __le16 wIELength;
-       u8 IEData[];
-} __attribute__((packed));
-
-/* DAA Energy Detected notification. [WHCI 0.96] section 3.1.4.14. */
-struct uwb_rc_evt_daa_energy_detected {
-       struct uwb_rceb rceb;
-       __le16 wLength;
-       u8 bandID;
-       u8 reserved;
-       u8 toneBmp[16];
-} __attribute__((packed));
-
-
-/**
- * Radio Control Interface Class Descriptor
- *
- *  WUSB 1.0 [8.6.1.2]
- */
-struct uwb_rc_control_intf_class_desc {
-       u8 bLength;
-       u8 bDescriptorType;
-       __le16 bcdRCIVersion;
-} __attribute__((packed));
-
-#endif /* #ifndef __LINUX__UWB_SPEC_H__ */
diff --git a/include/linux/uwb/umc.h b/include/linux/uwb/umc.h
deleted file mode 100644 (file)
index ddbceb3..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * UWB Multi-interface Controller support.
- *
- * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
- *
- * UMC (UWB Multi-interface Controller) capabilities (e.g., radio
- * controller, host controller) are presented as devices on the "umc"
- * bus.
- *
- * The radio controller is not strictly a UMC capability but it's
- * useful to present it as such.
- *
- * References:
- *
- *   [WHCI] Wireless Host Controller Interface Specification for
- *          Certified Wireless Universal Serial Bus, revision 0.95.
- *
- * How this works is kind of convoluted but simple. The whci.ko driver
- * loads when WHCI devices are detected. These WHCI devices expose
- * many devices in the same PCI function (they couldn't have reused
- * functions, no), so for each PCI function that exposes these many
- * devices, whci ceates a umc_dev [whci_probe() -> whci_add_cap()]
- * with umc_device_create() and adds it to the bus with
- * umc_device_register().
- *
- * umc_device_register() calls device_register() which will push the
- * bus management code to load your UMC driver's somehting_probe()
- * that you have registered for that capability code.
- *
- * Now when the WHCI device is removed, whci_remove() will go over
- * each umc_dev assigned to each of the PCI function's capabilities
- * and through whci_del_cap() call umc_device_unregister() each
- * created umc_dev. Of course, if you are bound to the device, your
- * driver's something_remove() will be called.
- */
-
-#ifndef _LINUX_UWB_UMC_H_
-#define _LINUX_UWB_UMC_H_
-
-#include <linux/device.h>
-#include <linux/pci.h>
-
-/*
- * UMC capability IDs.
- *
- * 0x00 is reserved so use it for the radio controller device.
- *
- * [WHCI] table 2-8
- */
-#define UMC_CAP_ID_WHCI_RC      0x00 /* radio controller */
-#define UMC_CAP_ID_WHCI_WUSB_HC 0x01 /* WUSB host controller */
-
-/**
- * struct umc_dev - UMC capability device
- *
- * @version:  version of the specification this capability conforms to.
- * @cap_id:   capability ID.
- * @bar:      PCI Bar (64 bit) where the resource lies
- * @resource: register space resource.
- * @irq:      interrupt line.
- */
-struct umc_dev {
-       u16             version;
-       u8              cap_id;
-       u8              bar;
-       struct resource resource;
-       unsigned        irq;
-       struct device   dev;
-};
-
-#define to_umc_dev(d) container_of(d, struct umc_dev, dev)
-
-/**
- * struct umc_driver - UMC capability driver
- * @cap_id: supported capability ID.
- * @match: driver specific capability matching function.
- * @match_data: driver specific data for match() (e.g., a
- * table of pci_device_id's if umc_match_pci_id() is used).
- */
-struct umc_driver {
-       char *name;
-       u8 cap_id;
-       int (*match)(struct umc_driver *, struct umc_dev *);
-       const void *match_data;
-
-       int  (*probe)(struct umc_dev *);
-       void (*remove)(struct umc_dev *);
-       int  (*pre_reset)(struct umc_dev *);
-       int  (*post_reset)(struct umc_dev *);
-
-       struct device_driver driver;
-};
-
-#define to_umc_driver(d) container_of(d, struct umc_driver, driver)
-
-extern struct bus_type umc_bus_type;
-
-struct umc_dev *umc_device_create(struct device *parent, int n);
-int __must_check umc_device_register(struct umc_dev *umc);
-void umc_device_unregister(struct umc_dev *umc);
-
-int __must_check __umc_driver_register(struct umc_driver *umc_drv,
-                                      struct module *mod,
-                                      const char *mod_name);
-
-/**
- * umc_driver_register - register a UMC capabiltity driver.
- * @umc_drv:  pointer to the driver.
- */
-#define umc_driver_register(umc_drv) \
-       __umc_driver_register(umc_drv, THIS_MODULE, KBUILD_MODNAME)
-
-void umc_driver_unregister(struct umc_driver *umc_drv);
-
-/*
- * Utility function you can use to match (umc_driver->match) against a
- * null-terminated array of 'struct pci_device_id' in
- * umc_driver->match_data.
- */
-int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc);
-
-/**
- * umc_parent_pci_dev - return the UMC's parent PCI device or NULL if none
- * @umc_dev: UMC device whose parent PCI device we are looking for
- *
- * DIRTY!!! DON'T RELY ON THIS
- *
- * FIXME: This is as dirty as it gets, but we need some way to check
- * the correct type of umc_dev->parent (so that for example, we can
- * cast to pci_dev). Casting to pci_dev is necessary because at some
- * point we need to request resources from the device. Mapping is
- * easily over come (ioremap and stuff are bus agnostic), but hooking
- * up to some error handlers (such as pci error handlers) might need
- * this.
- *
- * THIS might (probably will) be removed in the future, so don't count
- * on it.
- */
-static inline struct pci_dev *umc_parent_pci_dev(struct umc_dev *umc_dev)
-{
-       struct pci_dev *pci_dev = NULL;
-       if (dev_is_pci(umc_dev->dev.parent))
-               pci_dev = to_pci_dev(umc_dev->dev.parent);
-       return pci_dev;
-}
-
-/**
- * umc_dev_get() - reference a UMC device.
- * @umc_dev: Pointer to UMC device.
- *
- * NOTE: we are assuming in this whole scheme that the parent device
- *       is referenced at _probe() time and unreferenced at _remove()
- *       time by the parent's subsystem.
- */
-static inline struct umc_dev *umc_dev_get(struct umc_dev *umc_dev)
-{
-       get_device(&umc_dev->dev);
-       return umc_dev;
-}
-
-/**
- * umc_dev_put() - unreference a UMC device.
- * @umc_dev: Pointer to UMC device.
- */
-static inline void umc_dev_put(struct umc_dev *umc_dev)
-{
-       put_device(&umc_dev->dev);
-}
-
-/**
- * umc_set_drvdata - set UMC device's driver data.
- * @umc_dev: Pointer to UMC device.
- * @data:    Data to set.
- */
-static inline void umc_set_drvdata(struct umc_dev *umc_dev, void *data)
-{
-       dev_set_drvdata(&umc_dev->dev, data);
-}
-
-/**
- * umc_get_drvdata - recover UMC device's driver data.
- * @umc_dev: Pointer to UMC device.
- */
-static inline void *umc_get_drvdata(struct umc_dev *umc_dev)
-{
-       return dev_get_drvdata(&umc_dev->dev);
-}
-
-int umc_controller_reset(struct umc_dev *umc);
-
-#endif /* #ifndef _LINUX_UWB_UMC_H_ */
diff --git a/include/linux/uwb/whci.h b/include/linux/uwb/whci.h
deleted file mode 100644 (file)
index 1a5c2cc..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Wireless Host Controller Interface for Ultra-Wide-Band and Wireless USB
- *
- * Copyright (C) 2005-2006 Intel Corporation
- * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
- *
- * References:
- *   [WHCI] Wireless Host Controller Interface Specification for
- *          Certified Wireless Universal Serial Bus, revision 0.95.
- */
-#ifndef _LINUX_UWB_WHCI_H_
-#define _LINUX_UWB_WHCI_H_
-
-#include <linux/pci.h>
-
-/*
- * UWB interface capability registers (offsets from UWBBASE)
- *
- * [WHCI] section 2.2
- */
-#define UWBCAPINFO     0x00 /* == UWBCAPDATA(0) */
-#  define UWBCAPINFO_TO_N_CAPS(c)      (((c) >> 0)  & 0xFull)
-#define UWBCAPDATA(n)  (8*(n))
-#  define UWBCAPDATA_TO_VERSION(c)     (((c) >> 32) & 0xFFFFull)
-#  define UWBCAPDATA_TO_OFFSET(c)      (((c) >> 18) & 0x3FFFull)
-#  define UWBCAPDATA_TO_BAR(c)         (((c) >> 16) & 0x3ull)
-#  define UWBCAPDATA_TO_SIZE(c)                ((((c) >> 8) & 0xFFull) * sizeof(u32))
-#  define UWBCAPDATA_TO_CAP_ID(c)      (((c) >> 0)  & 0xFFull)
-
-/* Size of the WHCI capability data (including the RC capability) for
-   a device with n capabilities. */
-#define UWBCAPDATA_SIZE(n) (8 + 8*(n))
-
-
-/*
- * URC registers (offsets from URCBASE)
- *
- * [WHCI] section 2.3
- */
-#define URCCMD         0x00
-#  define URCCMD_RESET         (1 << 31)  /* UMC Hardware reset */
-#  define URCCMD_RS            (1 << 30)  /* Run/Stop */
-#  define URCCMD_EARV          (1 << 29)  /* Event Address Register Valid */
-#  define URCCMD_ACTIVE                (1 << 15)  /* Command is active */
-#  define URCCMD_IWR           (1 << 14)  /* Interrupt When Ready */
-#  define URCCMD_SIZE_MASK     0x00000fff /* Command size mask */
-#define URCSTS         0x04
-#  define URCSTS_EPS           (1 << 17)  /* Event Processing Status */
-#  define URCSTS_HALTED                (1 << 16)  /* RC halted */
-#  define URCSTS_HSE           (1 << 10)  /* Host System Error...fried */
-#  define URCSTS_ER            (1 <<  9)  /* Event Ready */
-#  define URCSTS_RCI           (1 <<  8)  /* Ready for Command Interrupt */
-#  define URCSTS_INT_MASK      0x00000700 /* URC interrupt sources */
-#  define URCSTS_ISI           0x000000ff /* Interrupt Source Identification */
-#define URCINTR                0x08
-#  define URCINTR_EN_ALL       0x000007ff /* Enable all interrupt sources */
-#define URCCMDADDR     0x10
-#define URCEVTADDR     0x18
-#  define URCEVTADDR_OFFSET_MASK 0xfff    /* Event pointer offset mask */
-
-
-/** Write 32 bit @value to little endian register at @addr */
-static inline
-void le_writel(u32 value, void __iomem *addr)
-{
-       iowrite32(value, addr);
-}
-
-
-/** Read from 32 bit little endian register at @addr */
-static inline
-u32 le_readl(void __iomem *addr)
-{
-       return ioread32(addr);
-}
-
-
-/** Write 64 bit @value to little endian register at @addr */
-static inline
-void le_writeq(u64 value, void __iomem *addr)
-{
-       iowrite32(value, addr);
-       iowrite32(value >> 32, addr + 4);
-}
-
-
-/** Read from 64 bit little endian register at @addr */
-static inline
-u64 le_readq(void __iomem *addr)
-{
-       u64 value;
-       value  = ioread32(addr);
-       value |= (u64)ioread32(addr + 4) << 32;
-       return value;
-}
-
-extern int whci_wait_for(struct device *dev, u32 __iomem *reg,
-                        u32 mask, u32 result,
-                        unsigned long max_ms,  const char *tag);
-
-#endif /* #ifndef _LINUX_UWB_WHCI_H_ */