mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 22:51:42 +00:00
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
b1bc81a0ef
@ -437,3 +437,10 @@ Why: Superseded by tdfxfb. I2C/DDC support used to live in a separate
|
|||||||
driver but this caused driver conflicts.
|
driver but this caused driver conflicts.
|
||||||
Who: Jean Delvare <khali@linux-fr.org>
|
Who: Jean Delvare <khali@linux-fr.org>
|
||||||
Krzysztof Helt <krzysztof.h1@wp.pl>
|
Krzysztof Helt <krzysztof.h1@wp.pl>
|
||||||
|
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
What: CONFIG_RFKILL_INPUT
|
||||||
|
When: 2.6.33
|
||||||
|
Why: Should be implemented in userspace, policy daemon.
|
||||||
|
Who: Johannes Berg <johannes@sipsolutions.net>
|
||||||
|
@ -1,571 +1,136 @@
|
|||||||
rfkill - RF switch subsystem support
|
rfkill - RF kill switch support
|
||||||
====================================
|
===============================
|
||||||
|
|
||||||
1 Introduction
|
1. Introduction
|
||||||
2 Implementation details
|
2. Implementation details
|
||||||
3 Kernel driver guidelines
|
3. Kernel driver guidelines
|
||||||
3.1 wireless device drivers
|
4. Kernel API
|
||||||
3.2 platform/switch drivers
|
5. Userspace support
|
||||||
3.3 input device drivers
|
|
||||||
4 Kernel API
|
|
||||||
5 Userspace support
|
|
||||||
|
|
||||||
|
|
||||||
1. Introduction:
|
1. Introduction
|
||||||
|
|
||||||
The rfkill switch subsystem exists to add a generic interface to circuitry that
|
The rfkill subsystem provides a generic interface to disabling any radio
|
||||||
can enable or disable the signal output of a wireless *transmitter* of any
|
transmitter in the system. When a transmitter is blocked, it shall not
|
||||||
type. By far, the most common use is to disable radio-frequency transmitters.
|
radiate any power.
|
||||||
|
|
||||||
Note that disabling the signal output means that the the transmitter is to be
|
The subsystem also provides the ability to react on button presses and
|
||||||
made to not emit any energy when "blocked". rfkill is not about blocking data
|
disable all transmitters of a certain type (or all). This is intended for
|
||||||
transmissions, it is about blocking energy emission.
|
situations where transmitters need to be turned off, for example on
|
||||||
|
aircraft.
|
||||||
|
|
||||||
The rfkill subsystem offers support for keys and switches often found on
|
|
||||||
laptops to enable wireless devices like WiFi and Bluetooth, so that these keys
|
|
||||||
and switches actually perform an action in all wireless devices of a given type
|
|
||||||
attached to the system.
|
|
||||||
|
|
||||||
The buttons to enable and disable the wireless transmitters are important in
|
|
||||||
situations where the user is for example using his laptop on a location where
|
|
||||||
radio-frequency transmitters _must_ be disabled (e.g. airplanes).
|
|
||||||
|
|
||||||
Because of this requirement, userspace support for the keys should not be made
|
2. Implementation details
|
||||||
mandatory. Because userspace might want to perform some additional smarter
|
|
||||||
tasks when the key is pressed, rfkill provides userspace the possibility to
|
|
||||||
take over the task to handle the key events.
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
2: Implementation details
|
|
||||||
|
|
||||||
The rfkill subsystem is composed of various components: the rfkill class, the
|
The rfkill subsystem is composed of various components: the rfkill class, the
|
||||||
rfkill-input module (an input layer handler), and some specific input layer
|
rfkill-input module (an input layer handler), and some specific input layer
|
||||||
events.
|
events.
|
||||||
|
|
||||||
The rfkill class provides kernel drivers with an interface that allows them to
|
The rfkill class is provided for kernel drivers to register their radio
|
||||||
know when they should enable or disable a wireless network device transmitter.
|
transmitter with the kernel, provide methods for turning it on and off and,
|
||||||
This is enabled by the CONFIG_RFKILL Kconfig option.
|
optionally, letting the system know about hardware-disabled states that may
|
||||||
|
be implemented on the device. This code is enabled with the CONFIG_RFKILL
|
||||||
|
Kconfig option, which drivers can "select".
|
||||||
|
|
||||||
The rfkill class support makes sure userspace will be notified of all state
|
The rfkill class code also notifies userspace of state changes, this is
|
||||||
changes on rfkill devices through uevents. It provides a notification chain
|
achieved via uevents. It also provides some sysfs files for userspace to
|
||||||
for interested parties in the kernel to also get notified of rfkill state
|
check the status of radio transmitters. See the "Userspace support" section
|
||||||
changes in other drivers. It creates several sysfs entries which can be used
|
below.
|
||||||
by userspace. See section "Userspace support".
|
|
||||||
|
|
||||||
The rfkill-input module provides the kernel with the ability to implement a
|
|
||||||
basic response when the user presses a key or button (or toggles a switch)
|
|
||||||
related to rfkill functionality. It is an in-kernel implementation of default
|
|
||||||
policy of reacting to rfkill-related input events and neither mandatory nor
|
|
||||||
required for wireless drivers to operate. It is enabled by the
|
|
||||||
CONFIG_RFKILL_INPUT Kconfig option.
|
|
||||||
|
|
||||||
rfkill-input is a rfkill-related events input layer handler. This handler will
|
The rfkill-input code implements a basic response to rfkill buttons -- it
|
||||||
listen to all rfkill key events and will change the rfkill state of the
|
implements turning on/off all devices of a certain class (or all).
|
||||||
wireless devices accordingly. With this option enabled userspace could either
|
|
||||||
do nothing or simply perform monitoring tasks.
|
|
||||||
|
|
||||||
The rfkill-input module also provides EPO (emergency power-off) functionality
|
When the device is hard-blocked (either by a call to rfkill_set_hw_state()
|
||||||
for all wireless transmitters. This function cannot be overridden, and it is
|
or from query_hw_block) set_block() will be invoked but drivers can well
|
||||||
always active. rfkill EPO is related to *_RFKILL_ALL input layer events.
|
ignore the method call since they can use the return value of the function
|
||||||
|
rfkill_set_hw_state() to sync the software state instead of keeping track
|
||||||
|
of calls to set_block().
|
||||||
|
|
||||||
|
|
||||||
Important terms for the rfkill subsystem:
|
The entire functionality is spread over more than one subsystem:
|
||||||
|
|
||||||
In order to avoid confusion, we avoid the term "switch" in rfkill when it is
|
* The kernel input layer generates KEY_WWAN, KEY_WLAN etc. and
|
||||||
referring to an electronic control circuit that enables or disables a
|
SW_RFKILL_ALL -- when the user presses a button. Drivers for radio
|
||||||
transmitter. We reserve it for the physical device a human manipulates
|
transmitters generally do not register to the input layer, unless the
|
||||||
(which is an input device, by the way):
|
device really provides an input device (i.e. a button that has no
|
||||||
|
effect other than generating a button press event)
|
||||||
|
|
||||||
rfkill switch:
|
* The rfkill-input code hooks up to these events and switches the soft-block
|
||||||
|
of the various radio transmitters, depending on the button type.
|
||||||
|
|
||||||
A physical device a human manipulates. Its state can be perceived by
|
* The rfkill drivers turn off/on their transmitters as requested.
|
||||||
the kernel either directly (through a GPIO pin, ACPI GPE) or by its
|
|
||||||
effect on a rfkill line of a wireless device.
|
|
||||||
|
|
||||||
rfkill controller:
|
* The rfkill class will generate userspace notifications (uevents) to tell
|
||||||
|
userspace what the current state is.
|
||||||
|
|
||||||
A hardware circuit that controls the state of a rfkill line, which a
|
|
||||||
kernel driver can interact with *to modify* that state (i.e. it has
|
|
||||||
either write-only or read/write access).
|
|
||||||
|
|
||||||
rfkill line:
|
|
||||||
|
|
||||||
An input channel (hardware or software) of a wireless device, which
|
3. Kernel driver guidelines
|
||||||
causes a wireless transmitter to stop emitting energy (BLOCK) when it
|
|
||||||
is active. Point of view is extremely important here: rfkill lines are
|
|
||||||
always seen from the PoV of a wireless device (and its driver).
|
|
||||||
|
|
||||||
soft rfkill line/software rfkill line:
|
|
||||||
|
|
||||||
A rfkill line the wireless device driver can directly change the state
|
Drivers for radio transmitters normally implement only the rfkill class.
|
||||||
of. Related to rfkill_state RFKILL_STATE_SOFT_BLOCKED.
|
These drivers may not unblock the transmitter based on own decisions, they
|
||||||
|
should act on information provided by the rfkill class only.
|
||||||
|
|
||||||
hard rfkill line/hardware rfkill line:
|
Platform drivers might implement input devices if the rfkill button is just
|
||||||
|
that, a button. If that button influences the hardware then you need to
|
||||||
|
implement an rfkill class instead. This also applies if the platform provides
|
||||||
|
a way to turn on/off the transmitter(s).
|
||||||
|
|
||||||
A rfkill line that works fully in hardware or firmware, and that cannot
|
During suspend/hibernation, transmitters should only be left enabled when
|
||||||
be overridden by the kernel driver. The hardware device or the
|
wake-on wlan or similar functionality requires it and the device wasn't
|
||||||
firmware just exports its status to the driver, but it is read-only.
|
blocked before suspend/hibernate. Note that it may be necessary to update
|
||||||
Related to rfkill_state RFKILL_STATE_HARD_BLOCKED.
|
the rfkill subsystem's idea of what the current state is at resume time if
|
||||||
|
the state may have changed over suspend.
|
||||||
|
|
||||||
The enum rfkill_state describes the rfkill state of a transmitter:
|
|
||||||
|
|
||||||
When a rfkill line or rfkill controller is in the RFKILL_STATE_UNBLOCKED state,
|
|
||||||
the wireless transmitter (radio TX circuit for example) is *enabled*. When the
|
|
||||||
it is in the RFKILL_STATE_SOFT_BLOCKED or RFKILL_STATE_HARD_BLOCKED, the
|
|
||||||
wireless transmitter is to be *blocked* from operating.
|
|
||||||
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED indicates that a call to toggle_radio() can change
|
4. Kernel API
|
||||||
that state. RFKILL_STATE_HARD_BLOCKED indicates that a call to toggle_radio()
|
|
||||||
will not be able to change the state and will return with a suitable error if
|
|
||||||
attempts are made to set the state to RFKILL_STATE_UNBLOCKED.
|
|
||||||
|
|
||||||
RFKILL_STATE_HARD_BLOCKED is used by drivers to signal that the device is
|
|
||||||
locked in the BLOCKED state by a hardwire rfkill line (typically an input pin
|
|
||||||
that, when active, forces the transmitter to be disabled) which the driver
|
|
||||||
CANNOT override.
|
|
||||||
|
|
||||||
Full rfkill functionality requires two different subsystems to cooperate: the
|
|
||||||
input layer and the rfkill class. The input layer issues *commands* to the
|
|
||||||
entire system requesting that devices registered to the rfkill class change
|
|
||||||
state. The way this interaction happens is not complex, but it is not obvious
|
|
||||||
either:
|
|
||||||
|
|
||||||
Kernel Input layer:
|
|
||||||
|
|
||||||
* Generates KEY_WWAN, KEY_WLAN, KEY_BLUETOOTH, SW_RFKILL_ALL, and
|
|
||||||
other such events when the user presses certain keys, buttons, or
|
|
||||||
toggles certain physical switches.
|
|
||||||
|
|
||||||
THE INPUT LAYER IS NEVER USED TO PROPAGATE STATUS, NOTIFICATIONS OR THE
|
|
||||||
KIND OF STUFF AN ON-SCREEN-DISPLAY APPLICATION WOULD REPORT. It is
|
|
||||||
used to issue *commands* for the system to change behaviour, and these
|
|
||||||
commands may or may not be carried out by some kernel driver or
|
|
||||||
userspace application. It follows that doing user feedback based only
|
|
||||||
on input events is broken, as there is no guarantee that an input event
|
|
||||||
will be acted upon.
|
|
||||||
|
|
||||||
Most wireless communication device drivers implementing rfkill
|
|
||||||
functionality MUST NOT generate these events, and have no reason to
|
|
||||||
register themselves with the input layer. Doing otherwise is a common
|
|
||||||
misconception. There is an API to propagate rfkill status change
|
|
||||||
information, and it is NOT the input layer.
|
|
||||||
|
|
||||||
rfkill class:
|
|
||||||
|
|
||||||
* Calls a hook in a driver to effectively change the wireless
|
|
||||||
transmitter state;
|
|
||||||
* Keeps track of the wireless transmitter state (with help from
|
|
||||||
the driver);
|
|
||||||
* Generates userspace notifications (uevents) and a call to a
|
|
||||||
notification chain (kernel) when there is a wireless transmitter
|
|
||||||
state change;
|
|
||||||
* Connects a wireless communications driver with the common rfkill
|
|
||||||
control system, which, for example, allows actions such as
|
|
||||||
"switch all bluetooth devices offline" to be carried out by
|
|
||||||
userspace or by rfkill-input.
|
|
||||||
|
|
||||||
THE RFKILL CLASS NEVER ISSUES INPUT EVENTS. THE RFKILL CLASS DOES
|
|
||||||
NOT LISTEN TO INPUT EVENTS. NO DRIVER USING THE RFKILL CLASS SHALL
|
|
||||||
EVER LISTEN TO, OR ACT ON RFKILL INPUT EVENTS. Doing otherwise is
|
|
||||||
a layering violation.
|
|
||||||
|
|
||||||
Most wireless data communication drivers in the kernel have just to
|
|
||||||
implement the rfkill class API to work properly. Interfacing to the
|
|
||||||
input layer is not often required (and is very often a *bug*) on
|
|
||||||
wireless drivers.
|
|
||||||
|
|
||||||
Platform drivers often have to attach to the input layer to *issue*
|
|
||||||
(but never to listen to) rfkill events for rfkill switches, and also to
|
|
||||||
the rfkill class to export a control interface for the platform rfkill
|
|
||||||
controllers to the rfkill subsystem. This does NOT mean the rfkill
|
|
||||||
switch is attached to a rfkill class (doing so is almost always wrong).
|
|
||||||
It just means the same kernel module is the driver for different
|
|
||||||
devices (rfkill switches and rfkill controllers).
|
|
||||||
|
|
||||||
|
|
||||||
Userspace input handlers (uevents) or kernel input handlers (rfkill-input):
|
|
||||||
|
|
||||||
* Implements the policy of what should happen when one of the input
|
|
||||||
layer events related to rfkill operation is received.
|
|
||||||
* Uses the sysfs interface (userspace) or private rfkill API calls
|
|
||||||
to tell the devices registered with the rfkill class to change
|
|
||||||
their state (i.e. translates the input layer event into real
|
|
||||||
action).
|
|
||||||
|
|
||||||
* rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0
|
|
||||||
(power off all transmitters) in a special way: it ignores any
|
|
||||||
overrides and local state cache and forces all transmitters to the
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED state (including those which are already
|
|
||||||
supposed to be BLOCKED).
|
|
||||||
* rfkill EPO will remain active until rfkill-input receives an
|
|
||||||
EV_SW SW_RFKILL_ALL 1 event. While the EPO is active, transmitters
|
|
||||||
are locked in the blocked state (rfkill will refuse to unblock them).
|
|
||||||
* rfkill-input implements different policies that the user can
|
|
||||||
select for handling EV_SW SW_RFKILL_ALL 1. It will unlock rfkill,
|
|
||||||
and either do nothing (leave transmitters blocked, but now unlocked),
|
|
||||||
restore the transmitters to their state before the EPO, or unblock
|
|
||||||
them all.
|
|
||||||
|
|
||||||
Userspace uevent handler or kernel platform-specific drivers hooked to the
|
|
||||||
rfkill notifier chain:
|
|
||||||
|
|
||||||
* Taps into the rfkill notifier chain or to KOBJ_CHANGE uevents,
|
|
||||||
in order to know when a device that is registered with the rfkill
|
|
||||||
class changes state;
|
|
||||||
* Issues feedback notifications to the user;
|
|
||||||
* In the rare platforms where this is required, synthesizes an input
|
|
||||||
event to command all *OTHER* rfkill devices to also change their
|
|
||||||
statues when a specific rfkill device changes state.
|
|
||||||
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
3: Kernel driver guidelines
|
|
||||||
|
|
||||||
Remember: point-of-view is everything for a driver that connects to the rfkill
|
|
||||||
subsystem. All the details below must be measured/perceived from the point of
|
|
||||||
view of the specific driver being modified.
|
|
||||||
|
|
||||||
The first thing one needs to know is whether his driver should be talking to
|
|
||||||
the rfkill class or to the input layer. In rare cases (platform drivers), it
|
|
||||||
could happen that you need to do both, as platform drivers often handle a
|
|
||||||
variety of devices in the same driver.
|
|
||||||
|
|
||||||
Do not mistake input devices for rfkill controllers. The only type of "rfkill
|
|
||||||
switch" device that is to be registered with the rfkill class are those
|
|
||||||
directly controlling the circuits that cause a wireless transmitter to stop
|
|
||||||
working (or the software equivalent of them), i.e. what we call a rfkill
|
|
||||||
controller. Every other kind of "rfkill switch" is just an input device and
|
|
||||||
MUST NOT be registered with the rfkill class.
|
|
||||||
|
|
||||||
A driver should register a device with the rfkill class when ALL of the
|
|
||||||
following conditions are met (they define a rfkill controller):
|
|
||||||
|
|
||||||
1. The device is/controls a data communications wireless transmitter;
|
|
||||||
|
|
||||||
2. The kernel can interact with the hardware/firmware to CHANGE the wireless
|
|
||||||
transmitter state (block/unblock TX operation);
|
|
||||||
|
|
||||||
3. The transmitter can be made to not emit any energy when "blocked":
|
|
||||||
rfkill is not about blocking data transmissions, it is about blocking
|
|
||||||
energy emission;
|
|
||||||
|
|
||||||
A driver should register a device with the input subsystem to issue
|
|
||||||
rfkill-related events (KEY_WLAN, KEY_BLUETOOTH, KEY_WWAN, KEY_WIMAX,
|
|
||||||
SW_RFKILL_ALL, etc) when ALL of the folowing conditions are met:
|
|
||||||
|
|
||||||
1. It is directly related to some physical device the user interacts with, to
|
|
||||||
command the O.S./firmware/hardware to enable/disable a data communications
|
|
||||||
wireless transmitter.
|
|
||||||
|
|
||||||
Examples of the physical device are: buttons, keys and switches the user
|
|
||||||
will press/touch/slide/switch to enable or disable the wireless
|
|
||||||
communication device.
|
|
||||||
|
|
||||||
2. It is NOT slaved to another device, i.e. there is no other device that
|
|
||||||
issues rfkill-related input events in preference to this one.
|
|
||||||
|
|
||||||
Please refer to the corner cases and examples section for more details.
|
|
||||||
|
|
||||||
When in doubt, do not issue input events. For drivers that should generate
|
|
||||||
input events in some platforms, but not in others (e.g. b43), the best solution
|
|
||||||
is to NEVER generate input events in the first place. That work should be
|
|
||||||
deferred to a platform-specific kernel module (which will know when to generate
|
|
||||||
events through the rfkill notifier chain) or to userspace. This avoids the
|
|
||||||
usual maintenance problems with DMI whitelisting.
|
|
||||||
|
|
||||||
|
|
||||||
Corner cases and examples:
|
|
||||||
====================================
|
|
||||||
|
|
||||||
1. If the device is an input device that, because of hardware or firmware,
|
|
||||||
causes wireless transmitters to be blocked regardless of the kernel's will, it
|
|
||||||
is still just an input device, and NOT to be registered with the rfkill class.
|
|
||||||
|
|
||||||
2. If the wireless transmitter switch control is read-only, it is an input
|
|
||||||
device and not to be registered with the rfkill class (and maybe not to be made
|
|
||||||
an input layer event source either, see below).
|
|
||||||
|
|
||||||
3. If there is some other device driver *closer* to the actual hardware the
|
|
||||||
user interacted with (the button/switch/key) to issue an input event, THAT is
|
|
||||||
the device driver that should be issuing input events.
|
|
||||||
|
|
||||||
E.g:
|
|
||||||
[RFKILL slider switch] -- [GPIO hardware] -- [WLAN card rf-kill input]
|
|
||||||
(platform driver) (wireless card driver)
|
|
||||||
|
|
||||||
The user is closer to the RFKILL slide switch plaform driver, so the driver
|
|
||||||
which must issue input events is the platform driver looking at the GPIO
|
|
||||||
hardware, and NEVER the wireless card driver (which is just a slave). It is
|
|
||||||
very likely that there are other leaves than just the WLAN card rf-kill input
|
|
||||||
(e.g. a bluetooth card, etc)...
|
|
||||||
|
|
||||||
On the other hand, some embedded devices do this:
|
|
||||||
|
|
||||||
[RFKILL slider switch] -- [WLAN card rf-kill input]
|
|
||||||
(wireless card driver)
|
|
||||||
|
|
||||||
In this situation, the wireless card driver *could* register itself as an input
|
|
||||||
device and issue rf-kill related input events... but in order to AVOID the need
|
|
||||||
for DMI whitelisting, the wireless card driver does NOT do it. Userspace (HAL)
|
|
||||||
or a platform driver (that exists only on these embedded devices) will do the
|
|
||||||
dirty job of issuing the input events.
|
|
||||||
|
|
||||||
|
|
||||||
COMMON MISTAKES in kernel drivers, related to rfkill:
|
|
||||||
====================================
|
|
||||||
|
|
||||||
1. NEVER confuse input device keys and buttons with input device switches.
|
|
||||||
|
|
||||||
1a. Switches are always set or reset. They report the current state
|
|
||||||
(on position or off position).
|
|
||||||
|
|
||||||
1b. Keys and buttons are either in the pressed or not-pressed state, and
|
|
||||||
that's it. A "button" that latches down when you press it, and
|
|
||||||
unlatches when you press it again is in fact a switch as far as input
|
|
||||||
devices go.
|
|
||||||
|
|
||||||
Add the SW_* events you need for switches, do NOT try to emulate a button using
|
|
||||||
KEY_* events just because there is no such SW_* event yet. Do NOT try to use,
|
|
||||||
for example, KEY_BLUETOOTH when you should be using SW_BLUETOOTH instead.
|
|
||||||
|
|
||||||
2. Input device switches (sources of EV_SW events) DO store their current state
|
|
||||||
(so you *must* initialize it by issuing a gratuitous input layer event on
|
|
||||||
driver start-up and also when resuming from sleep), and that state CAN be
|
|
||||||
queried from userspace through IOCTLs. There is no sysfs interface for this,
|
|
||||||
but that doesn't mean you should break things trying to hook it to the rfkill
|
|
||||||
class to get a sysfs interface :-)
|
|
||||||
|
|
||||||
3. Do not issue *_RFKILL_ALL events by default, unless you are sure it is the
|
|
||||||
correct event for your switch/button. These events are emergency power-off
|
|
||||||
events when they are trying to turn the transmitters off. An example of an
|
|
||||||
input device which SHOULD generate *_RFKILL_ALL events is the wireless-kill
|
|
||||||
switch in a laptop which is NOT a hotkey, but a real sliding/rocker switch.
|
|
||||||
An example of an input device which SHOULD NOT generate *_RFKILL_ALL events by
|
|
||||||
default, is any sort of hot key that is type-specific (e.g. the one for WLAN).
|
|
||||||
|
|
||||||
|
|
||||||
3.1 Guidelines for wireless device drivers
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
(in this text, rfkill->foo means the foo field of struct rfkill).
|
|
||||||
|
|
||||||
1. Each independent transmitter in a wireless device (usually there is only one
|
|
||||||
transmitter per device) should have a SINGLE rfkill class attached to it.
|
|
||||||
|
|
||||||
2. If the device does not have any sort of hardware assistance to allow the
|
|
||||||
driver to rfkill the device, the driver should emulate it by taking all actions
|
|
||||||
required to silence the transmitter.
|
|
||||||
|
|
||||||
3. If it is impossible to silence the transmitter (i.e. it still emits energy,
|
|
||||||
even if it is just in brief pulses, when there is no data to transmit and there
|
|
||||||
is no hardware support to turn it off) do NOT lie to the users. Do not attach
|
|
||||||
it to a rfkill class. The rfkill subsystem does not deal with data
|
|
||||||
transmission, it deals with energy emission. If the transmitter is emitting
|
|
||||||
energy, it is not blocked in rfkill terms.
|
|
||||||
|
|
||||||
4. It doesn't matter if the device has multiple rfkill input lines affecting
|
|
||||||
the same transmitter, their combined state is to be exported as a single state
|
|
||||||
per transmitter (see rule 1).
|
|
||||||
|
|
||||||
This rule exists because users of the rfkill subsystem expect to get (and set,
|
|
||||||
when possible) the overall transmitter rfkill state, not of a particular rfkill
|
|
||||||
line.
|
|
||||||
|
|
||||||
5. The wireless device driver MUST NOT leave the transmitter enabled during
|
|
||||||
suspend and hibernation unless:
|
|
||||||
|
|
||||||
5.1. The transmitter has to be enabled for some sort of functionality
|
|
||||||
like wake-on-wireless-packet or autonomous packed forwarding in a mesh
|
|
||||||
network, and that functionality is enabled for this suspend/hibernation
|
|
||||||
cycle.
|
|
||||||
|
|
||||||
AND
|
|
||||||
|
|
||||||
5.2. The device was not on a user-requested BLOCKED state before
|
|
||||||
the suspend (i.e. the driver must NOT unblock a device, not even
|
|
||||||
to support wake-on-wireless-packet or remain in the mesh).
|
|
||||||
|
|
||||||
In other words, there is absolutely no allowed scenario where a driver can
|
|
||||||
automatically take action to unblock a rfkill controller (obviously, this deals
|
|
||||||
with scenarios where soft-blocking or both soft and hard blocking is happening.
|
|
||||||
Scenarios where hardware rfkill lines are the only ones blocking the
|
|
||||||
transmitter are outside of this rule, since the wireless device driver does not
|
|
||||||
control its input hardware rfkill lines in the first place).
|
|
||||||
|
|
||||||
6. During resume, rfkill will try to restore its previous state.
|
|
||||||
|
|
||||||
7. After a rfkill class is suspended, it will *not* call rfkill->toggle_radio
|
|
||||||
until it is resumed.
|
|
||||||
|
|
||||||
|
|
||||||
Example of a WLAN wireless driver connected to the rfkill subsystem:
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
|
|
||||||
A certain WLAN card has one input pin that causes it to block the transmitter
|
|
||||||
and makes the status of that input pin available (only for reading!) to the
|
|
||||||
kernel driver. This is a hard rfkill input line (it cannot be overridden by
|
|
||||||
the kernel driver).
|
|
||||||
|
|
||||||
The card also has one PCI register that, if manipulated by the driver, causes
|
|
||||||
it to block the transmitter. This is a soft rfkill input line.
|
|
||||||
|
|
||||||
It has also a thermal protection circuitry that shuts down its transmitter if
|
|
||||||
the card overheats, and makes the status of that protection available (only for
|
|
||||||
reading!) to the kernel driver. This is also a hard rfkill input line.
|
|
||||||
|
|
||||||
If either one of these rfkill lines are active, the transmitter is blocked by
|
|
||||||
the hardware and forced offline.
|
|
||||||
|
|
||||||
The driver should allocate and attach to its struct device *ONE* instance of
|
|
||||||
the rfkill class (there is only one transmitter).
|
|
||||||
|
|
||||||
It can implement the get_state() hook, and return RFKILL_STATE_HARD_BLOCKED if
|
|
||||||
either one of its two hard rfkill input lines are active. If the two hard
|
|
||||||
rfkill lines are inactive, it must return RFKILL_STATE_SOFT_BLOCKED if its soft
|
|
||||||
rfkill input line is active. Only if none of the rfkill input lines are
|
|
||||||
active, will it return RFKILL_STATE_UNBLOCKED.
|
|
||||||
|
|
||||||
Since the device has a hardware rfkill line, it IS subject to state changes
|
|
||||||
external to rfkill. Therefore, the driver must make sure that it calls
|
|
||||||
rfkill_force_state() to keep the status always up-to-date, and it must do a
|
|
||||||
rfkill_force_state() on resume from sleep.
|
|
||||||
|
|
||||||
Every time the driver gets a notification from the card that one of its rfkill
|
|
||||||
lines changed state (polling might be needed on badly designed cards that don't
|
|
||||||
generate interrupts for such events), it recomputes the rfkill state as per
|
|
||||||
above, and calls rfkill_force_state() to update it.
|
|
||||||
|
|
||||||
The driver should implement the toggle_radio() hook, that:
|
|
||||||
|
|
||||||
1. Returns an error if one of the hardware rfkill lines are active, and the
|
|
||||||
caller asked for RFKILL_STATE_UNBLOCKED.
|
|
||||||
|
|
||||||
2. Activates the soft rfkill line if the caller asked for state
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED. It should do this even if one of the hard rfkill
|
|
||||||
lines are active, effectively double-blocking the transmitter.
|
|
||||||
|
|
||||||
3. Deactivates the soft rfkill line if none of the hardware rfkill lines are
|
|
||||||
active and the caller asked for RFKILL_STATE_UNBLOCKED.
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
4: Kernel API
|
|
||||||
|
|
||||||
To build a driver with rfkill subsystem support, the driver should depend on
|
To build a driver with rfkill subsystem support, the driver should depend on
|
||||||
(or select) the Kconfig symbol RFKILL; it should _not_ depend on RKFILL_INPUT.
|
(or select) the Kconfig symbol RFKILL.
|
||||||
|
|
||||||
The hardware the driver talks to may be write-only (where the current state
|
The hardware the driver talks to may be write-only (where the current state
|
||||||
of the hardware is unknown), or read-write (where the hardware can be queried
|
of the hardware is unknown), or read-write (where the hardware can be queried
|
||||||
about its current state).
|
about its current state).
|
||||||
|
|
||||||
The rfkill class will call the get_state hook of a device every time it needs
|
Calling rfkill_set_hw_state() when a state change happens is required from
|
||||||
to know the *real* current state of the hardware. This can happen often, but
|
rfkill drivers that control devices that can be hard-blocked unless they also
|
||||||
it does not do any polling, so it is not enough on hardware that is subject
|
assign the poll_hw_block() callback (then the rfkill core will poll the
|
||||||
to state changes outside of the rfkill subsystem.
|
device). Don't do this unless you cannot get the event in any other way.
|
||||||
|
|
||||||
Therefore, calling rfkill_force_state() when a state change happens is
|
|
||||||
mandatory when the device has a hardware rfkill line, or when something else
|
|
||||||
like the firmware could cause its state to be changed without going through the
|
|
||||||
rfkill class.
|
|
||||||
|
|
||||||
Some hardware provides events when its status changes. In these cases, it is
|
|
||||||
best for the driver to not provide a get_state hook, and instead register the
|
|
||||||
rfkill class *already* with the correct status, and keep it updated using
|
|
||||||
rfkill_force_state() when it gets an event from the hardware.
|
|
||||||
|
|
||||||
rfkill_force_state() must be used on the device resume handlers to update the
|
5. Userspace support
|
||||||
rfkill status, should there be any chance of the device status changing during
|
|
||||||
the sleep.
|
|
||||||
|
|
||||||
There is no provision for a statically-allocated rfkill struct. You must
|
The following sysfs entries exist for every rfkill device:
|
||||||
use rfkill_allocate() to allocate one.
|
|
||||||
|
|
||||||
You should:
|
|
||||||
- rfkill_allocate()
|
|
||||||
- modify rfkill fields (flags, name)
|
|
||||||
- modify state to the current hardware state (THIS IS THE ONLY TIME
|
|
||||||
YOU CAN ACCESS state DIRECTLY)
|
|
||||||
- rfkill_register()
|
|
||||||
|
|
||||||
The only way to set a device to the RFKILL_STATE_HARD_BLOCKED state is through
|
|
||||||
a suitable return of get_state() or through rfkill_force_state().
|
|
||||||
|
|
||||||
When a device is in the RFKILL_STATE_HARD_BLOCKED state, the only way to switch
|
|
||||||
it to a different state is through a suitable return of get_state() or through
|
|
||||||
rfkill_force_state().
|
|
||||||
|
|
||||||
If toggle_radio() is called to set a device to state RFKILL_STATE_SOFT_BLOCKED
|
|
||||||
when that device is already at the RFKILL_STATE_HARD_BLOCKED state, it should
|
|
||||||
not return an error. Instead, it should try to double-block the transmitter,
|
|
||||||
so that its state will change from RFKILL_STATE_HARD_BLOCKED to
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED should the hardware blocking cease.
|
|
||||||
|
|
||||||
Please refer to the source for more documentation.
|
|
||||||
|
|
||||||
===============================================================================
|
|
||||||
5: Userspace support
|
|
||||||
|
|
||||||
rfkill devices issue uevents (with an action of "change"), with the following
|
|
||||||
environment variables set:
|
|
||||||
|
|
||||||
RFKILL_NAME
|
|
||||||
RFKILL_STATE
|
|
||||||
RFKILL_TYPE
|
|
||||||
|
|
||||||
The ABI for these variables is defined by the sysfs attributes. It is best
|
|
||||||
to take a quick look at the source to make sure of the possible values.
|
|
||||||
|
|
||||||
It is expected that HAL will trap those, and bridge them to DBUS, etc. These
|
|
||||||
events CAN and SHOULD be used to give feedback to the user about the rfkill
|
|
||||||
status of the system.
|
|
||||||
|
|
||||||
Input devices may issue events that are related to rfkill. These are the
|
|
||||||
various KEY_* events and SW_* events supported by rfkill-input.c.
|
|
||||||
|
|
||||||
Userspace may not change the state of an rfkill switch in response to an
|
|
||||||
input event, it should refrain from changing states entirely.
|
|
||||||
|
|
||||||
Userspace cannot assume it is the only source of control for rfkill switches.
|
|
||||||
Their state can change due to firmware actions, direct user actions, and the
|
|
||||||
rfkill-input EPO override for *_RFKILL_ALL.
|
|
||||||
|
|
||||||
When rfkill-input is not active, userspace must initiate a rfkill status
|
|
||||||
change by writing to the "state" attribute in order for anything to happen.
|
|
||||||
|
|
||||||
Take particular care to implement EV_SW SW_RFKILL_ALL properly. When that
|
|
||||||
switch is set to OFF, *every* rfkill device *MUST* be immediately put into the
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED state, no questions asked.
|
|
||||||
|
|
||||||
The following sysfs entries will be created:
|
|
||||||
|
|
||||||
name: Name assigned by driver to this key (interface or driver name).
|
name: Name assigned by driver to this key (interface or driver name).
|
||||||
type: Name of the key type ("wlan", "bluetooth", etc).
|
type: Name of the key type ("wlan", "bluetooth", etc).
|
||||||
state: Current state of the transmitter
|
state: Current state of the transmitter
|
||||||
0: RFKILL_STATE_SOFT_BLOCKED
|
0: RFKILL_STATE_SOFT_BLOCKED
|
||||||
transmitter is forced off, but one can override it
|
transmitter is turned off by software
|
||||||
by a write to the state attribute;
|
|
||||||
1: RFKILL_STATE_UNBLOCKED
|
1: RFKILL_STATE_UNBLOCKED
|
||||||
transmiter is NOT forced off, and may operate if
|
transmitter is (potentially) active
|
||||||
all other conditions for such operation are met
|
|
||||||
(such as interface is up and configured, etc);
|
|
||||||
2: RFKILL_STATE_HARD_BLOCKED
|
2: RFKILL_STATE_HARD_BLOCKED
|
||||||
transmitter is forced off by something outside of
|
transmitter is forced off by something outside of
|
||||||
the driver's control. One cannot set a device to
|
the driver's control.
|
||||||
this state through writes to the state attribute;
|
claim: 0: Kernel handles events (currently always reads that value)
|
||||||
claim: 1: Userspace handles events, 0: Kernel handles events
|
|
||||||
|
|
||||||
Both the "state" and "claim" entries are also writable. For the "state" entry
|
rfkill devices also issue uevents (with an action of "change"), with the
|
||||||
this means that when 1 or 0 is written, the device rfkill state (if not yet in
|
following environment variables set:
|
||||||
the requested state), will be will be toggled accordingly.
|
|
||||||
|
|
||||||
For the "claim" entry writing 1 to it means that the kernel no longer handles
|
RFKILL_NAME
|
||||||
key events even though RFKILL_INPUT input was enabled. When "claim" has been
|
RFKILL_STATE
|
||||||
set to 0, userspace should make sure that it listens for the input events or
|
RFKILL_TYPE
|
||||||
check the sysfs "state" entry regularly to correctly perform the required tasks
|
|
||||||
when the rkfill key is pressed.
|
|
||||||
|
|
||||||
A note about input devices and EV_SW events:
|
The contents of these variables corresponds to the "name", "state" and
|
||||||
|
"type" sysfs files explained above.
|
||||||
|
|
||||||
In order to know the current state of an input device switch (like
|
An alternative userspace interface exists as a misc device /dev/rfkill,
|
||||||
SW_RFKILL_ALL), you will need to use an IOCTL. That information is not
|
which allows userspace to obtain and set the state of rfkill devices and
|
||||||
available through sysfs in a generic way at this time, and it is not available
|
sets of devices. It also notifies userspace about device addition and
|
||||||
through the rfkill class AT ALL.
|
removal. The API is a simple read/write API that is defined in
|
||||||
|
linux/rfkill.h.
|
||||||
|
@ -4753,9 +4753,9 @@ S: Supported
|
|||||||
F: fs/reiserfs/
|
F: fs/reiserfs/
|
||||||
|
|
||||||
RFKILL
|
RFKILL
|
||||||
P: Ivo van Doorn
|
P: Johannes Berg
|
||||||
M: IvDoorn@gmail.com
|
M: johannes@sipsolutions.net
|
||||||
L: netdev@vger.kernel.org
|
L: linux-wireless@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F Documentation/rfkill.txt
|
F Documentation/rfkill.txt
|
||||||
F: net/rfkill/
|
F: net/rfkill/
|
||||||
|
@ -35,21 +35,25 @@ static void tosa_bt_off(struct tosa_bt_data *data)
|
|||||||
gpio_set_value(data->gpio_reset, 0);
|
gpio_set_value(data->gpio_reset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tosa_bt_toggle_radio(void *data, enum rfkill_state state)
|
static int tosa_bt_set_block(void *data, bool blocked)
|
||||||
{
|
{
|
||||||
pr_info("BT_RADIO going: %s\n",
|
pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on");
|
||||||
state == RFKILL_STATE_UNBLOCKED ? "on" : "off");
|
|
||||||
|
|
||||||
if (state == RFKILL_STATE_UNBLOCKED) {
|
if (!blocked) {
|
||||||
pr_info("TOSA_BT: going ON\n");
|
pr_info("TOSA_BT: going ON\n");
|
||||||
tosa_bt_on(data);
|
tosa_bt_on(data);
|
||||||
} else {
|
} else {
|
||||||
pr_info("TOSA_BT: going OFF\n");
|
pr_info("TOSA_BT: going OFF\n");
|
||||||
tosa_bt_off(data);
|
tosa_bt_off(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct rfkill_ops tosa_bt_rfkill_ops = {
|
||||||
|
.set_block = tosa_bt_set_block,
|
||||||
|
};
|
||||||
|
|
||||||
static int tosa_bt_probe(struct platform_device *dev)
|
static int tosa_bt_probe(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@ -70,18 +74,14 @@ static int tosa_bt_probe(struct platform_device *dev)
|
|||||||
if (rc)
|
if (rc)
|
||||||
goto err_pwr_dir;
|
goto err_pwr_dir;
|
||||||
|
|
||||||
rfk = rfkill_allocate(&dev->dev, RFKILL_TYPE_BLUETOOTH);
|
rfk = rfkill_alloc("tosa-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH,
|
||||||
|
&tosa_bt_rfkill_ops, data);
|
||||||
if (!rfk) {
|
if (!rfk) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto err_rfk_alloc;
|
goto err_rfk_alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rfk->name = "tosa-bt";
|
rfkill_set_led_trigger_name(rfk, "tosa-bt");
|
||||||
rfk->toggle_radio = tosa_bt_toggle_radio;
|
|
||||||
rfk->data = data;
|
|
||||||
#ifdef CONFIG_RFKILL_LEDS
|
|
||||||
rfk->led_trigger.name = "tosa-bt";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
rc = rfkill_register(rfk);
|
rc = rfkill_register(rfk);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -92,9 +92,7 @@ static int tosa_bt_probe(struct platform_device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_rfkill:
|
err_rfkill:
|
||||||
if (rfk)
|
rfkill_destroy(rfk);
|
||||||
rfkill_free(rfk);
|
|
||||||
rfk = NULL;
|
|
||||||
err_rfk_alloc:
|
err_rfk_alloc:
|
||||||
tosa_bt_off(data);
|
tosa_bt_off(data);
|
||||||
err_pwr_dir:
|
err_pwr_dir:
|
||||||
@ -113,8 +111,10 @@ static int __devexit tosa_bt_remove(struct platform_device *dev)
|
|||||||
|
|
||||||
platform_set_drvdata(dev, NULL);
|
platform_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
if (rfk)
|
if (rfk) {
|
||||||
rfkill_unregister(rfk);
|
rfkill_unregister(rfk);
|
||||||
|
rfkill_destroy(rfk);
|
||||||
|
}
|
||||||
rfk = NULL;
|
rfk = NULL;
|
||||||
|
|
||||||
tosa_bt_off(data);
|
tosa_bt_off(data);
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/pda_power.h>
|
#include <linux/pda_power.h>
|
||||||
#include <linux/rfkill.h>
|
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
|
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
|
@ -2481,10 +2481,10 @@ static int add_net_device(struct hso_device *hso_dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hso_radio_toggle(void *data, enum rfkill_state state)
|
static int hso_rfkill_set_block(void *data, bool blocked)
|
||||||
{
|
{
|
||||||
struct hso_device *hso_dev = data;
|
struct hso_device *hso_dev = data;
|
||||||
int enabled = (state == RFKILL_STATE_UNBLOCKED);
|
int enabled = !blocked;
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
mutex_lock(&hso_dev->mutex);
|
mutex_lock(&hso_dev->mutex);
|
||||||
@ -2498,6 +2498,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct rfkill_ops hso_rfkill_ops = {
|
||||||
|
.set_block = hso_rfkill_set_block,
|
||||||
|
};
|
||||||
|
|
||||||
/* Creates and sets up everything for rfkill */
|
/* Creates and sets up everything for rfkill */
|
||||||
static void hso_create_rfkill(struct hso_device *hso_dev,
|
static void hso_create_rfkill(struct hso_device *hso_dev,
|
||||||
struct usb_interface *interface)
|
struct usb_interface *interface)
|
||||||
@ -2506,29 +2510,25 @@ static void hso_create_rfkill(struct hso_device *hso_dev,
|
|||||||
struct device *dev = &hso_net->net->dev;
|
struct device *dev = &hso_net->net->dev;
|
||||||
char *rfkn;
|
char *rfkn;
|
||||||
|
|
||||||
hso_net->rfkill = rfkill_allocate(&interface_to_usbdev(interface)->dev,
|
|
||||||
RFKILL_TYPE_WWAN);
|
|
||||||
if (!hso_net->rfkill) {
|
|
||||||
dev_err(dev, "%s - Out of memory\n", __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rfkn = kzalloc(20, GFP_KERNEL);
|
rfkn = kzalloc(20, GFP_KERNEL);
|
||||||
if (!rfkn) {
|
if (!rfkn)
|
||||||
rfkill_free(hso_net->rfkill);
|
|
||||||
hso_net->rfkill = NULL;
|
|
||||||
dev_err(dev, "%s - Out of memory\n", __func__);
|
dev_err(dev, "%s - Out of memory\n", __func__);
|
||||||
return;
|
|
||||||
}
|
|
||||||
snprintf(rfkn, 20, "hso-%d",
|
snprintf(rfkn, 20, "hso-%d",
|
||||||
interface->altsetting->desc.bInterfaceNumber);
|
interface->altsetting->desc.bInterfaceNumber);
|
||||||
hso_net->rfkill->name = rfkn;
|
|
||||||
hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED;
|
hso_net->rfkill = rfkill_alloc(rfkn,
|
||||||
hso_net->rfkill->data = hso_dev;
|
&interface_to_usbdev(interface)->dev,
|
||||||
hso_net->rfkill->toggle_radio = hso_radio_toggle;
|
RFKILL_TYPE_WWAN,
|
||||||
if (rfkill_register(hso_net->rfkill) < 0) {
|
&hso_rfkill_ops, hso_dev);
|
||||||
|
if (!hso_net->rfkill) {
|
||||||
|
dev_err(dev, "%s - Out of memory\n", __func__);
|
||||||
|
kfree(rfkn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rfkill_register(hso_net->rfkill) < 0) {
|
||||||
|
rfkill_destroy(hso_net->rfkill);
|
||||||
kfree(rfkn);
|
kfree(rfkn);
|
||||||
hso_net->rfkill->name = NULL;
|
|
||||||
rfkill_free(hso_net->rfkill);
|
|
||||||
hso_net->rfkill = NULL;
|
hso_net->rfkill = NULL;
|
||||||
dev_err(dev, "%s - Failed to register rfkill\n", __func__);
|
dev_err(dev, "%s - Failed to register rfkill\n", __func__);
|
||||||
return;
|
return;
|
||||||
@ -3165,8 +3165,10 @@ static void hso_free_interface(struct usb_interface *interface)
|
|||||||
hso_stop_net_device(network_table[i]);
|
hso_stop_net_device(network_table[i]);
|
||||||
cancel_work_sync(&network_table[i]->async_put_intf);
|
cancel_work_sync(&network_table[i]->async_put_intf);
|
||||||
cancel_work_sync(&network_table[i]->async_get_intf);
|
cancel_work_sync(&network_table[i]->async_get_intf);
|
||||||
if (rfk)
|
if (rfk) {
|
||||||
rfkill_unregister(rfk);
|
rfkill_unregister(rfk);
|
||||||
|
rfkill_destroy(rfk);
|
||||||
|
}
|
||||||
hso_free_net_device(network_table[i]);
|
hso_free_net_device(network_table[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,11 +333,11 @@ config USB_ZD1201
|
|||||||
config USB_NET_RNDIS_WLAN
|
config USB_NET_RNDIS_WLAN
|
||||||
tristate "Wireless RNDIS USB support"
|
tristate "Wireless RNDIS USB support"
|
||||||
depends on USB && WLAN_80211 && EXPERIMENTAL
|
depends on USB && WLAN_80211 && EXPERIMENTAL
|
||||||
|
depends on CFG80211
|
||||||
select USB_USBNET
|
select USB_USBNET
|
||||||
select USB_NET_CDCETHER
|
select USB_NET_CDCETHER
|
||||||
select USB_NET_RNDIS_HOST
|
select USB_NET_RNDIS_HOST
|
||||||
select WIRELESS_EXT
|
select WIRELESS_EXT
|
||||||
select CFG80211
|
|
||||||
---help---
|
---help---
|
||||||
This is a driver for wireless RNDIS devices.
|
This is a driver for wireless RNDIS devices.
|
||||||
These are USB based adapters found in devices such as:
|
These are USB based adapters found in devices such as:
|
||||||
|
@ -91,6 +91,7 @@ struct ar9170_led {
|
|||||||
struct led_classdev l;
|
struct led_classdev l;
|
||||||
char name[32];
|
char name[32];
|
||||||
unsigned int toggled;
|
unsigned int toggled;
|
||||||
|
bool last_state;
|
||||||
bool registered;
|
bool registered;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -101,7 +102,6 @@ enum ar9170_device_state {
|
|||||||
AR9170_STOPPED,
|
AR9170_STOPPED,
|
||||||
AR9170_IDLE,
|
AR9170_IDLE,
|
||||||
AR9170_STARTED,
|
AR9170_STARTED,
|
||||||
AR9170_ASSOCIATED,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ar9170_rxstream_mpdu_merge {
|
struct ar9170_rxstream_mpdu_merge {
|
||||||
@ -140,7 +140,7 @@ struct ar9170 {
|
|||||||
struct work_struct filter_config_work;
|
struct work_struct filter_config_work;
|
||||||
u64 cur_mc_hash, want_mc_hash;
|
u64 cur_mc_hash, want_mc_hash;
|
||||||
u32 cur_filter, want_filter;
|
u32 cur_filter, want_filter;
|
||||||
unsigned int filter_changed;
|
unsigned long filter_changed;
|
||||||
unsigned int filter_state;
|
unsigned int filter_state;
|
||||||
bool sniffer_enabled;
|
bool sniffer_enabled;
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ struct ar9170_sta_info {
|
|||||||
#define IS_STARTED(a) (a->state >= AR9170_STARTED)
|
#define IS_STARTED(a) (a->state >= AR9170_STARTED)
|
||||||
#define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE)
|
#define IS_ACCEPTING_CMD(a) (a->state >= AR9170_IDLE)
|
||||||
|
|
||||||
#define AR9170_FILTER_CHANGED_PROMISC BIT(0)
|
#define AR9170_FILTER_CHANGED_MODE BIT(0)
|
||||||
#define AR9170_FILTER_CHANGED_MULTICAST BIT(1)
|
#define AR9170_FILTER_CHANGED_MULTICAST BIT(1)
|
||||||
#define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2)
|
#define AR9170_FILTER_CHANGED_FRAMEFILTER BIT(2)
|
||||||
|
|
||||||
@ -206,6 +206,7 @@ void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb);
|
|||||||
void ar9170_unregister(struct ar9170 *ar);
|
void ar9170_unregister(struct ar9170 *ar);
|
||||||
void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
|
void ar9170_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
|
||||||
bool update_statistics, u16 tx_status);
|
bool update_statistics, u16 tx_status);
|
||||||
|
void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
|
||||||
|
|
||||||
/* MAC */
|
/* MAC */
|
||||||
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
int ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||||
@ -215,6 +216,9 @@ int ar9170_update_multicast(struct ar9170 *ar);
|
|||||||
int ar9170_update_frame_filter(struct ar9170 *ar);
|
int ar9170_update_frame_filter(struct ar9170 *ar);
|
||||||
int ar9170_set_operating_mode(struct ar9170 *ar);
|
int ar9170_set_operating_mode(struct ar9170 *ar);
|
||||||
int ar9170_set_beacon_timers(struct ar9170 *ar);
|
int ar9170_set_beacon_timers(struct ar9170 *ar);
|
||||||
|
int ar9170_set_dyn_sifs_ack(struct ar9170 *ar);
|
||||||
|
int ar9170_set_slot_time(struct ar9170 *ar);
|
||||||
|
int ar9170_set_basic_rates(struct ar9170 *ar);
|
||||||
int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry);
|
int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry);
|
||||||
int ar9170_update_beacon(struct ar9170 *ar);
|
int ar9170_update_beacon(struct ar9170 *ar);
|
||||||
void ar9170_new_beacon(struct work_struct *work);
|
void ar9170_new_beacon(struct work_struct *work);
|
||||||
|
@ -207,7 +207,8 @@ enum ar9170_cmd {
|
|||||||
#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44)
|
#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44)
|
||||||
#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48)
|
#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48)
|
||||||
|
|
||||||
#define AR9170_MAC_REG_AMPDU_SET (AR9170_MAC_REG_BASE + 0xba0)
|
#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C)
|
||||||
|
#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0)
|
||||||
|
|
||||||
#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00)
|
#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00)
|
||||||
#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50)
|
#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50)
|
||||||
@ -376,7 +377,6 @@ static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t)
|
|||||||
#define AR9170_RX_ERROR_FATAL 0x80
|
#define AR9170_RX_ERROR_FATAL 0x80
|
||||||
|
|
||||||
struct ar9170_cmd_tx_status {
|
struct ar9170_cmd_tx_status {
|
||||||
__le16 unkn;
|
|
||||||
u8 dst[ETH_ALEN];
|
u8 dst[ETH_ALEN];
|
||||||
__le32 rate;
|
__le32 rate;
|
||||||
__le16 status;
|
__le16 status;
|
||||||
@ -394,6 +394,7 @@ struct ar9170_cmd_ba_failed_count {
|
|||||||
struct ar9170_cmd_response {
|
struct ar9170_cmd_response {
|
||||||
u8 flag;
|
u8 flag;
|
||||||
u8 type;
|
u8 type;
|
||||||
|
__le16 padding;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct ar9170_cmd_tx_status tx_status;
|
struct ar9170_cmd_tx_status tx_status;
|
||||||
|
@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work)
|
|||||||
|
|
||||||
mutex_lock(&ar->mutex);
|
mutex_lock(&ar->mutex);
|
||||||
for (i = 0; i < AR9170_NUM_LEDS; i++)
|
for (i = 0; i < AR9170_NUM_LEDS; i++)
|
||||||
if (ar->leds[i].toggled) {
|
if (ar->leds[i].registered && ar->leds[i].toggled) {
|
||||||
led_val |= 1 << i;
|
led_val |= 1 << i;
|
||||||
|
|
||||||
tmp = 70 + 200 / (ar->leds[i].toggled);
|
tmp = 70 + 200 / (ar->leds[i].toggled);
|
||||||
@ -101,9 +101,15 @@ static void ar9170_led_brightness_set(struct led_classdev *led,
|
|||||||
struct ar9170_led *arl = container_of(led, struct ar9170_led, l);
|
struct ar9170_led *arl = container_of(led, struct ar9170_led, l);
|
||||||
struct ar9170 *ar = arl->ar;
|
struct ar9170 *ar = arl->ar;
|
||||||
|
|
||||||
arl->toggled++;
|
if (unlikely(!arl->registered))
|
||||||
|
return ;
|
||||||
|
|
||||||
if (likely(IS_ACCEPTING_CMD(ar) && brightness))
|
if (arl->last_state != !!brightness) {
|
||||||
|
arl->toggled++;
|
||||||
|
arl->last_state = !!brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
|
||||||
queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10);
|
queue_delayed_work(ar->hw->workqueue, &ar->led_work, HZ/10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
cancel_delayed_work_sync(&ar->led_work);
|
|
||||||
|
|
||||||
for (i = 0; i < AR9170_NUM_LEDS; i++)
|
for (i = 0; i < AR9170_NUM_LEDS; i++)
|
||||||
if (ar->leds[i].registered) {
|
if (ar->leds[i].registered) {
|
||||||
led_classdev_unregister(&ar->leds[i].l);
|
led_classdev_unregister(&ar->leds[i].l);
|
||||||
ar->leds[i].registered = false;
|
ar->leds[i].registered = false;
|
||||||
|
ar->leds[i].toggled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cancel_delayed_work_sync(&ar->led_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ar9170_register_leds(struct ar9170 *ar)
|
int ar9170_register_leds(struct ar9170 *ar)
|
||||||
|
@ -38,6 +38,55 @@
|
|||||||
#include "ar9170.h"
|
#include "ar9170.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
|
|
||||||
|
int ar9170_set_dyn_sifs_ack(struct ar9170 *ar)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
if (conf_is_ht40(&ar->hw->conf))
|
||||||
|
val = 0x010a;
|
||||||
|
else {
|
||||||
|
if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
|
||||||
|
val = 0x105;
|
||||||
|
else
|
||||||
|
val = 0x104;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ar9170_set_slot_time(struct ar9170 *ar)
|
||||||
|
{
|
||||||
|
u32 slottime = 20;
|
||||||
|
|
||||||
|
if (!ar->vif)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) ||
|
||||||
|
ar->vif->bss_conf.use_short_slot)
|
||||||
|
slottime = 9;
|
||||||
|
|
||||||
|
return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ar9170_set_basic_rates(struct ar9170 *ar)
|
||||||
|
{
|
||||||
|
u8 cck, ofdm;
|
||||||
|
|
||||||
|
if (!ar->vif)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ofdm = ar->vif->bss_conf.basic_rates >> 4;
|
||||||
|
|
||||||
|
/* FIXME: is still necessary? */
|
||||||
|
if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
|
||||||
|
cck = 0;
|
||||||
|
else
|
||||||
|
cck = ar->vif->bss_conf.basic_rates & 0xf;
|
||||||
|
|
||||||
|
return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE,
|
||||||
|
ofdm << 8 | cck);
|
||||||
|
}
|
||||||
|
|
||||||
int ar9170_set_qos(struct ar9170 *ar)
|
int ar9170_set_qos(struct ar9170 *ar)
|
||||||
{
|
{
|
||||||
ar9170_regwrite_begin(ar);
|
ar9170_regwrite_begin(ar);
|
||||||
@ -84,7 +133,7 @@ static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity)
|
|||||||
val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0);
|
val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0);
|
||||||
|
|
||||||
ar9170_regwrite_begin(ar);
|
ar9170_regwrite_begin(ar);
|
||||||
ar9170_regwrite(AR9170_MAC_REG_AMPDU_SET, val);
|
ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val);
|
||||||
ar9170_regwrite_finish();
|
ar9170_regwrite_finish();
|
||||||
|
|
||||||
return ar9170_regwrite_result();
|
return ar9170_regwrite_result();
|
||||||
@ -398,10 +447,10 @@ int ar9170_update_beacon(struct ar9170 *ar)
|
|||||||
/* XXX: use skb->cb info */
|
/* XXX: use skb->cb info */
|
||||||
if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
|
if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
|
||||||
ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
|
ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
|
||||||
((skb->len + 4) << (3+16)) + 0x0400);
|
((skb->len + 4) << (3 + 16)) + 0x0400);
|
||||||
else
|
else
|
||||||
ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
|
ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
|
||||||
((skb->len + 4) << (3+16)) + 0x0400);
|
((skb->len + 4) << 16) + 0x001b);
|
||||||
|
|
||||||
ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4);
|
ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4);
|
||||||
ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS);
|
ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS);
|
||||||
|
@ -146,7 +146,6 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
|
|||||||
{ \
|
{ \
|
||||||
.ht_supported = true, \
|
.ht_supported = true, \
|
||||||
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \
|
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \
|
||||||
IEEE80211_HT_CAP_SM_PS | \
|
|
||||||
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
|
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
|
||||||
IEEE80211_HT_CAP_SGI_40 | \
|
IEEE80211_HT_CAP_SGI_40 | \
|
||||||
IEEE80211_HT_CAP_DSSSCCK40 | \
|
IEEE80211_HT_CAP_DSSSCCK40 | \
|
||||||
@ -344,7 +343,6 @@ static void ar9170_tx_status_janitor(struct work_struct *work)
|
|||||||
if (unlikely(!IS_STARTED(ar)))
|
if (unlikely(!IS_STARTED(ar)))
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
mutex_lock(&ar->mutex);
|
|
||||||
/* recycle the garbage back to mac80211... one by one. */
|
/* recycle the garbage back to mac80211... one by one. */
|
||||||
while ((skb = skb_dequeue(&ar->global_tx_status_waste))) {
|
while ((skb = skb_dequeue(&ar->global_tx_status_waste))) {
|
||||||
#ifdef AR9170_QUEUE_DEBUG
|
#ifdef AR9170_QUEUE_DEBUG
|
||||||
@ -370,12 +368,9 @@ static void ar9170_tx_status_janitor(struct work_struct *work)
|
|||||||
if (skb_queue_len(&ar->global_tx_status_waste) > 0)
|
if (skb_queue_len(&ar->global_tx_status_waste) > 0)
|
||||||
queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
|
queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
|
||||||
msecs_to_jiffies(100));
|
msecs_to_jiffies(100));
|
||||||
|
|
||||||
mutex_unlock(&ar->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ar9170_handle_command_response(struct ar9170 *ar,
|
void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
|
||||||
void *buf, u32 len)
|
|
||||||
{
|
{
|
||||||
struct ar9170_cmd_response *cmd = (void *) buf;
|
struct ar9170_cmd_response *cmd = (void *) buf;
|
||||||
|
|
||||||
@ -957,6 +952,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
|
|||||||
|
|
||||||
mutex_lock(&ar->mutex);
|
mutex_lock(&ar->mutex);
|
||||||
|
|
||||||
|
ar->filter_changed = 0;
|
||||||
|
|
||||||
/* reinitialize queues statistics */
|
/* reinitialize queues statistics */
|
||||||
memset(&ar->tx_stats, 0, sizeof(ar->tx_stats));
|
memset(&ar->tx_stats, 0, sizeof(ar->tx_stats));
|
||||||
for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++)
|
for (i = 0; i < ARRAY_SIZE(ar->tx_stats); i++)
|
||||||
@ -1012,10 +1009,10 @@ static void ar9170_op_stop(struct ieee80211_hw *hw)
|
|||||||
|
|
||||||
flush_workqueue(ar->hw->workqueue);
|
flush_workqueue(ar->hw->workqueue);
|
||||||
|
|
||||||
mutex_lock(&ar->mutex);
|
|
||||||
cancel_delayed_work_sync(&ar->tx_status_janitor);
|
cancel_delayed_work_sync(&ar->tx_status_janitor);
|
||||||
cancel_work_sync(&ar->filter_config_work);
|
cancel_work_sync(&ar->filter_config_work);
|
||||||
cancel_work_sync(&ar->beacon_work);
|
cancel_work_sync(&ar->beacon_work);
|
||||||
|
mutex_lock(&ar->mutex);
|
||||||
skb_queue_purge(&ar->global_tx_status_waste);
|
skb_queue_purge(&ar->global_tx_status_waste);
|
||||||
skb_queue_purge(&ar->global_tx_status);
|
skb_queue_purge(&ar->global_tx_status);
|
||||||
|
|
||||||
@ -1306,11 +1303,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
|
|
||||||
mutex_lock(&ar->mutex);
|
mutex_lock(&ar->mutex);
|
||||||
|
|
||||||
if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
|
|
||||||
/* TODO */
|
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
|
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
err = 0;
|
err = 0;
|
||||||
@ -1344,15 +1336,21 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
|
||||||
|
|
||||||
|
/* adjust slot time for 5 GHz */
|
||||||
|
err = ar9170_set_slot_time(ar);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
err = ar9170_set_dyn_sifs_ack(ar);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
err = ar9170_set_channel(ar, hw->conf.channel,
|
err = ar9170_set_channel(ar, hw->conf.channel,
|
||||||
AR9170_RFI_NONE,
|
AR9170_RFI_NONE,
|
||||||
nl80211_to_ar9170(hw->conf.channel_type));
|
nl80211_to_ar9170(hw->conf.channel_type));
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
/* adjust slot time for 5 GHz */
|
|
||||||
if (hw->conf.channel->band == IEEE80211_BAND_5GHZ)
|
|
||||||
err = ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME,
|
|
||||||
9 << 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -1370,20 +1368,26 @@ static void ar9170_set_filters(struct work_struct *work)
|
|||||||
return ;
|
return ;
|
||||||
|
|
||||||
mutex_lock(&ar->mutex);
|
mutex_lock(&ar->mutex);
|
||||||
if (ar->filter_changed & AR9170_FILTER_CHANGED_PROMISC) {
|
if (test_and_clear_bit(AR9170_FILTER_CHANGED_MODE,
|
||||||
|
&ar->filter_changed)) {
|
||||||
err = ar9170_set_operating_mode(ar);
|
err = ar9170_set_operating_mode(ar);
|
||||||
if (err)
|
if (err)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ar->filter_changed & AR9170_FILTER_CHANGED_MULTICAST) {
|
if (test_and_clear_bit(AR9170_FILTER_CHANGED_MULTICAST,
|
||||||
|
&ar->filter_changed)) {
|
||||||
err = ar9170_update_multicast(ar);
|
err = ar9170_update_multicast(ar);
|
||||||
if (err)
|
if (err)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ar->filter_changed & AR9170_FILTER_CHANGED_FRAMEFILTER)
|
if (test_and_clear_bit(AR9170_FILTER_CHANGED_FRAMEFILTER,
|
||||||
|
&ar->filter_changed)) {
|
||||||
err = ar9170_update_frame_filter(ar);
|
err = ar9170_update_frame_filter(ar);
|
||||||
|
if (err)
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&ar->mutex);
|
mutex_unlock(&ar->mutex);
|
||||||
@ -1413,7 +1417,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* always get broadcast frames */
|
/* always get broadcast frames */
|
||||||
mchash = 1ULL << (0xff>>2);
|
mchash = 1ULL << (0xff >> 2);
|
||||||
|
|
||||||
for (i = 0; i < mc_count; i++) {
|
for (i = 0; i < mc_count; i++) {
|
||||||
if (WARN_ON(!mclist))
|
if (WARN_ON(!mclist))
|
||||||
@ -1423,7 +1427,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
|
|||||||
}
|
}
|
||||||
ar->want_mc_hash = mchash;
|
ar->want_mc_hash = mchash;
|
||||||
}
|
}
|
||||||
ar->filter_changed |= AR9170_FILTER_CHANGED_MULTICAST;
|
set_bit(AR9170_FILTER_CHANGED_MULTICAST, &ar->filter_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed_flags & FIF_CONTROL) {
|
if (changed_flags & FIF_CONTROL) {
|
||||||
@ -1439,12 +1443,14 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
|
|||||||
else
|
else
|
||||||
ar->want_filter = ar->cur_filter & ~filter;
|
ar->want_filter = ar->cur_filter & ~filter;
|
||||||
|
|
||||||
ar->filter_changed |= AR9170_FILTER_CHANGED_FRAMEFILTER;
|
set_bit(AR9170_FILTER_CHANGED_FRAMEFILTER,
|
||||||
|
&ar->filter_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed_flags & FIF_PROMISC_IN_BSS) {
|
if (changed_flags & FIF_PROMISC_IN_BSS) {
|
||||||
ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0;
|
ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0;
|
||||||
ar->filter_changed |= AR9170_FILTER_CHANGED_PROMISC;
|
set_bit(AR9170_FILTER_CHANGED_MODE,
|
||||||
|
&ar->filter_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(IS_STARTED(ar)))
|
if (likely(IS_STARTED(ar)))
|
||||||
@ -1464,27 +1470,32 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||||||
if (changed & BSS_CHANGED_BSSID) {
|
if (changed & BSS_CHANGED_BSSID) {
|
||||||
memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN);
|
memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN);
|
||||||
err = ar9170_set_operating_mode(ar);
|
err = ar9170_set_operating_mode(ar);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) {
|
if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) {
|
||||||
err = ar9170_update_beacon(ar);
|
err = ar9170_update_beacon(ar);
|
||||||
if (!err)
|
if (err)
|
||||||
ar9170_set_beacon_timers(ar);
|
goto out;
|
||||||
|
|
||||||
|
err = ar9170_set_beacon_timers(ar);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ar9170_regwrite_begin(ar);
|
|
||||||
|
|
||||||
if (changed & BSS_CHANGED_ASSOC) {
|
if (changed & BSS_CHANGED_ASSOC) {
|
||||||
ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state;
|
|
||||||
|
|
||||||
#ifndef CONFIG_AR9170_LEDS
|
#ifndef CONFIG_AR9170_LEDS
|
||||||
/* enable assoc LED. */
|
/* enable assoc LED. */
|
||||||
err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0);
|
err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0);
|
||||||
#endif /* CONFIG_AR9170_LEDS */
|
#endif /* CONFIG_AR9170_LEDS */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed & BSS_CHANGED_BEACON_INT)
|
if (changed & BSS_CHANGED_BEACON_INT) {
|
||||||
err = ar9170_set_beacon_timers(ar);
|
err = ar9170_set_beacon_timers(ar);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (changed & BSS_CHANGED_HT) {
|
if (changed & BSS_CHANGED_HT) {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
@ -1492,31 +1503,18 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changed & BSS_CHANGED_ERP_SLOT) {
|
if (changed & BSS_CHANGED_ERP_SLOT) {
|
||||||
u32 slottime = 20;
|
err = ar9170_set_slot_time(ar);
|
||||||
|
if (err)
|
||||||
if (bss_conf->use_short_slot)
|
goto out;
|
||||||
slottime = 9;
|
|
||||||
|
|
||||||
ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed & BSS_CHANGED_BASIC_RATES) {
|
if (changed & BSS_CHANGED_BASIC_RATES) {
|
||||||
u32 cck, ofdm;
|
err = ar9170_set_basic_rates(ar);
|
||||||
|
if (err)
|
||||||
if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) {
|
goto out;
|
||||||
ofdm = bss_conf->basic_rates;
|
|
||||||
cck = 0;
|
|
||||||
} else {
|
|
||||||
/* four cck rates */
|
|
||||||
cck = bss_conf->basic_rates & 0xf;
|
|
||||||
ofdm = bss_conf->basic_rates >> 4;
|
|
||||||
}
|
|
||||||
ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE,
|
|
||||||
ofdm << 8 | cck);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ar9170_regwrite_finish();
|
out:
|
||||||
err = ar9170_regwrite_result();
|
|
||||||
mutex_unlock(&ar->mutex);
|
mutex_unlock(&ar->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +401,7 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
|
|||||||
int i, err;
|
int i, err;
|
||||||
u32 val;
|
u32 val;
|
||||||
bool is_2ghz = band == IEEE80211_BAND_2GHZ;
|
bool is_2ghz = band == IEEE80211_BAND_2GHZ;
|
||||||
bool is_40mhz = false; /* XXX: for now */
|
bool is_40mhz = conf_is_ht40(&ar->hw->conf);
|
||||||
|
|
||||||
ar9170_regwrite_begin(ar);
|
ar9170_regwrite_begin(ar);
|
||||||
|
|
||||||
@ -1200,7 +1200,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
|
|||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 /* 2 streams capable */)
|
if (ar->eeprom.tx_mask != 1)
|
||||||
tmp |= 0x100;
|
tmp |= 0x100;
|
||||||
|
|
||||||
err = ar9170_write_reg(ar, 0x1c5804, tmp);
|
err = ar9170_write_reg(ar, 0x1c5804, tmp);
|
||||||
@ -1214,7 +1214,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
|
|||||||
freqpar = ar9170_get_hw_dyn_params(channel, bw);
|
freqpar = ar9170_get_hw_dyn_params(channel, bw);
|
||||||
|
|
||||||
vals[0] = cpu_to_le32(channel->center_freq * 1000);
|
vals[0] = cpu_to_le32(channel->center_freq * 1000);
|
||||||
vals[1] = cpu_to_le32(bw == AR9170_BW_20 ? 0 : 1);
|
vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf));
|
||||||
vals[2] = cpu_to_le32(offs << 2 | 1);
|
vals[2] = cpu_to_le32(offs << 2 | 1);
|
||||||
vals[3] = cpu_to_le32(freqpar->coeff_exp);
|
vals[3] = cpu_to_le32(freqpar->coeff_exp);
|
||||||
vals[4] = cpu_to_le32(freqpar->coeff_man);
|
vals[4] = cpu_to_le32(freqpar->coeff_man);
|
||||||
|
@ -51,9 +51,14 @@ MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
|
|||||||
MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
|
MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless");
|
MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless");
|
||||||
|
MODULE_FIRMWARE("ar9170.fw");
|
||||||
MODULE_FIRMWARE("ar9170-1.fw");
|
MODULE_FIRMWARE("ar9170-1.fw");
|
||||||
MODULE_FIRMWARE("ar9170-2.fw");
|
MODULE_FIRMWARE("ar9170-2.fw");
|
||||||
|
|
||||||
|
enum ar9170_requirements {
|
||||||
|
AR9170_REQ_FW1_ONLY = 1,
|
||||||
|
};
|
||||||
|
|
||||||
static struct usb_device_id ar9170_usb_ids[] = {
|
static struct usb_device_id ar9170_usb_ids[] = {
|
||||||
/* Atheros 9170 */
|
/* Atheros 9170 */
|
||||||
{ USB_DEVICE(0x0cf3, 0x9170) },
|
{ USB_DEVICE(0x0cf3, 0x9170) },
|
||||||
@ -81,6 +86,10 @@ static struct usb_device_id ar9170_usb_ids[] = {
|
|||||||
{ USB_DEVICE(0x2019, 0x5304) },
|
{ USB_DEVICE(0x2019, 0x5304) },
|
||||||
/* IO-Data WNGDNUS2 */
|
/* IO-Data WNGDNUS2 */
|
||||||
{ USB_DEVICE(0x04bb, 0x093f) },
|
{ USB_DEVICE(0x04bb, 0x093f) },
|
||||||
|
/* AVM FRITZ!WLAN USB Stick N */
|
||||||
|
{ USB_DEVICE(0x057C, 0x8401) },
|
||||||
|
/* AVM FRITZ!WLAN USB Stick N 2.4 */
|
||||||
|
{ USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY },
|
||||||
|
|
||||||
/* terminate */
|
/* terminate */
|
||||||
{}
|
{}
|
||||||
@ -93,7 +102,7 @@ static void ar9170_usb_tx_urb_complete_free(struct urb *urb)
|
|||||||
struct ar9170_usb *aru = (struct ar9170_usb *)
|
struct ar9170_usb *aru = (struct ar9170_usb *)
|
||||||
usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
|
usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
|
||||||
|
|
||||||
if (!aru) {
|
if (unlikely(!aru)) {
|
||||||
dev_kfree_skb_irq(skb);
|
dev_kfree_skb_irq(skb);
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
@ -126,8 +135,8 @@ static void ar9170_usb_irq_completed(struct urb *urb)
|
|||||||
goto resubmit;
|
goto resubmit;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_hex_dump_bytes("ar9170 irq: ", DUMP_PREFIX_OFFSET,
|
ar9170_handle_command_response(&aru->common, urb->transfer_buffer,
|
||||||
urb->transfer_buffer, urb->actual_length);
|
urb->actual_length);
|
||||||
|
|
||||||
resubmit:
|
resubmit:
|
||||||
usb_anchor_urb(urb, &aru->rx_submitted);
|
usb_anchor_urb(urb, &aru->rx_submitted);
|
||||||
@ -177,16 +186,15 @@ resubmit:
|
|||||||
|
|
||||||
usb_anchor_urb(urb, &aru->rx_submitted);
|
usb_anchor_urb(urb, &aru->rx_submitted);
|
||||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
if (err) {
|
if (unlikely(err)) {
|
||||||
usb_unanchor_urb(urb);
|
usb_unanchor_urb(urb);
|
||||||
dev_kfree_skb_irq(skb);
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
free:
|
free:
|
||||||
dev_kfree_skb_irq(skb);
|
dev_kfree_skb_irq(skb);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru,
|
static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru,
|
||||||
@ -337,7 +345,7 @@ static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd,
|
|||||||
|
|
||||||
usb_anchor_urb(urb, &aru->tx_submitted);
|
usb_anchor_urb(urb, &aru->tx_submitted);
|
||||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
if (err) {
|
if (unlikely(err)) {
|
||||||
usb_unanchor_urb(urb);
|
usb_unanchor_urb(urb);
|
||||||
usb_free_urb(urb);
|
usb_free_urb(urb);
|
||||||
goto err_unbuf;
|
goto err_unbuf;
|
||||||
@ -418,7 +426,7 @@ static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u32 in, out;
|
u32 in, out;
|
||||||
|
|
||||||
if (!buffer)
|
if (unlikely(!buffer))
|
||||||
return ;
|
return ;
|
||||||
|
|
||||||
in = le32_to_cpup((__le32 *)buffer);
|
in = le32_to_cpup((__le32 *)buffer);
|
||||||
@ -504,17 +512,29 @@ static int ar9170_usb_request_firmware(struct ar9170_usb *aru)
|
|||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
err = request_firmware(&aru->firmware, "ar9170.fw",
|
||||||
|
&aru->udev->dev);
|
||||||
|
if (!err) {
|
||||||
|
aru->init_values = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aru->req_one_stage_fw) {
|
||||||
|
dev_err(&aru->udev->dev, "ar9170.fw firmware file "
|
||||||
|
"not found and is required for this device\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_err(&aru->udev->dev, "ar9170.fw firmware file "
|
||||||
|
"not found, trying old firmware...\n");
|
||||||
|
|
||||||
err = request_firmware(&aru->init_values, "ar9170-1.fw",
|
err = request_firmware(&aru->init_values, "ar9170-1.fw",
|
||||||
&aru->udev->dev);
|
&aru->udev->dev);
|
||||||
if (err) {
|
|
||||||
dev_err(&aru->udev->dev, "file with init values not found.\n");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev);
|
err = request_firmware(&aru->firmware, "ar9170-2.fw", &aru->udev->dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
release_firmware(aru->init_values);
|
release_firmware(aru->init_values);
|
||||||
dev_err(&aru->udev->dev, "firmware file not found.\n");
|
dev_err(&aru->udev->dev, "file with init values not found.\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,6 +568,9 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru)
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (!aru->init_values)
|
||||||
|
goto upload_fw_start;
|
||||||
|
|
||||||
/* First, upload initial values to device RAM */
|
/* First, upload initial values to device RAM */
|
||||||
err = ar9170_usb_upload(aru, aru->init_values->data,
|
err = ar9170_usb_upload(aru, aru->init_values->data,
|
||||||
aru->init_values->size, 0x102800, false);
|
aru->init_values->size, 0x102800, false);
|
||||||
@ -557,6 +580,8 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
upload_fw_start:
|
||||||
|
|
||||||
/* Then, upload the firmware itself and start it */
|
/* Then, upload the firmware itself and start it */
|
||||||
return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size,
|
return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size,
|
||||||
0x200000, true);
|
0x200000, true);
|
||||||
@ -656,6 +681,15 @@ err_out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool ar9170_requires_one_stage(const struct usb_device_id *id)
|
||||||
|
{
|
||||||
|
if (!id->driver_info)
|
||||||
|
return false;
|
||||||
|
if (id->driver_info == AR9170_REQ_FW1_ONLY)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int ar9170_usb_probe(struct usb_interface *intf,
|
static int ar9170_usb_probe(struct usb_interface *intf,
|
||||||
const struct usb_device_id *id)
|
const struct usb_device_id *id)
|
||||||
{
|
{
|
||||||
@ -676,6 +710,8 @@ static int ar9170_usb_probe(struct usb_interface *intf,
|
|||||||
aru->intf = intf;
|
aru->intf = intf;
|
||||||
ar = &aru->common;
|
ar = &aru->common;
|
||||||
|
|
||||||
|
aru->req_one_stage_fw = ar9170_requires_one_stage(id);
|
||||||
|
|
||||||
usb_set_intfdata(intf, aru);
|
usb_set_intfdata(intf, aru);
|
||||||
SET_IEEE80211_DEV(ar->hw, &udev->dev);
|
SET_IEEE80211_DEV(ar->hw, &udev->dev);
|
||||||
|
|
||||||
@ -691,7 +727,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
|
|||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
udev->reset_resume = 1;
|
udev->reset_resume = 1;
|
||||||
#endif
|
#endif /* CONFIG_PM */
|
||||||
err = ar9170_usb_reset(aru);
|
err = ar9170_usb_reset(aru);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_freehw;
|
goto err_freehw;
|
||||||
@ -776,11 +812,6 @@ static int ar9170_resume(struct usb_interface *intf)
|
|||||||
usb_unpoison_anchored_urbs(&aru->rx_submitted);
|
usb_unpoison_anchored_urbs(&aru->rx_submitted);
|
||||||
usb_unpoison_anchored_urbs(&aru->tx_submitted);
|
usb_unpoison_anchored_urbs(&aru->tx_submitted);
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: firmware upload will fail on resume.
|
|
||||||
* but this is better than a hang!
|
|
||||||
*/
|
|
||||||
|
|
||||||
err = ar9170_usb_init_device(aru);
|
err = ar9170_usb_init_device(aru);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_unrx;
|
goto err_unrx;
|
||||||
|
@ -62,6 +62,8 @@ struct ar9170_usb {
|
|||||||
struct usb_anchor rx_submitted;
|
struct usb_anchor rx_submitted;
|
||||||
struct usb_anchor tx_submitted;
|
struct usb_anchor tx_submitted;
|
||||||
|
|
||||||
|
bool req_one_stage_fw;
|
||||||
|
|
||||||
spinlock_t cmdlock;
|
spinlock_t cmdlock;
|
||||||
struct completion cmd_wait;
|
struct completion cmd_wait;
|
||||||
int readlen;
|
int readlen;
|
||||||
|
@ -2070,6 +2070,13 @@ err_unmap:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ath5k_beacon_disable(struct ath5k_softc *sc)
|
||||||
|
{
|
||||||
|
sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
|
||||||
|
ath5k_hw_set_imr(sc->ah, sc->imask);
|
||||||
|
ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Transmit a beacon frame at SWBA. Dynamic updates to the
|
* Transmit a beacon frame at SWBA. Dynamic updates to the
|
||||||
* frame contents are done as needed and the slot time is
|
* frame contents are done as needed and the slot time is
|
||||||
@ -2757,6 +2764,7 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
|
|||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
ath5k_hw_set_lladdr(sc->ah, mac);
|
ath5k_hw_set_lladdr(sc->ah, mac);
|
||||||
|
ath5k_beacon_disable(sc);
|
||||||
sc->vif = NULL;
|
sc->vif = NULL;
|
||||||
end:
|
end:
|
||||||
mutex_unlock(&sc->lock);
|
mutex_unlock(&sc->lock);
|
||||||
@ -2775,11 +2783,9 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
|
|
||||||
mutex_lock(&sc->lock);
|
mutex_lock(&sc->lock);
|
||||||
|
|
||||||
sc->bintval = conf->beacon_int;
|
|
||||||
|
|
||||||
ret = ath5k_chan_set(sc, conf->channel);
|
ret = ath5k_chan_set(sc, conf->channel);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto unlock;
|
||||||
|
|
||||||
if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
|
if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
|
||||||
(sc->power_level != conf->power_level)) {
|
(sc->power_level != conf->power_level)) {
|
||||||
@ -2808,8 +2814,9 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
*/
|
*/
|
||||||
ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
|
ath5k_hw_set_antenna_mode(ah, AR5K_ANTMODE_DEFAULT);
|
||||||
|
|
||||||
|
unlock:
|
||||||
mutex_unlock(&sc->lock);
|
mutex_unlock(&sc->lock);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SUPPORTED_FIF_FLAGS \
|
#define SUPPORTED_FIF_FLAGS \
|
||||||
@ -3061,7 +3068,14 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct ath5k_softc *sc = hw->priv;
|
struct ath5k_softc *sc = hw->priv;
|
||||||
struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
|
struct sk_buff *skb;
|
||||||
|
|
||||||
|
if (WARN_ON(!vif)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
skb = ieee80211_beacon_get(hw, vif);
|
||||||
|
|
||||||
if (!skb) {
|
if (!skb) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -460,12 +460,9 @@ struct ath_led {
|
|||||||
bool registered;
|
bool registered;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Rfkill */
|
|
||||||
#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */
|
|
||||||
|
|
||||||
struct ath_rfkill {
|
struct ath_rfkill {
|
||||||
struct rfkill *rfkill;
|
struct rfkill *rfkill;
|
||||||
struct delayed_work rfkill_poll;
|
struct rfkill_ops ops;
|
||||||
char rfkill_name[32];
|
char rfkill_name[32];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -509,8 +506,6 @@ struct ath_rfkill {
|
|||||||
#define SC_OP_RXFLUSH BIT(7)
|
#define SC_OP_RXFLUSH BIT(7)
|
||||||
#define SC_OP_LED_ASSOCIATED BIT(8)
|
#define SC_OP_LED_ASSOCIATED BIT(8)
|
||||||
#define SC_OP_RFKILL_REGISTERED BIT(9)
|
#define SC_OP_RFKILL_REGISTERED BIT(9)
|
||||||
#define SC_OP_RFKILL_SW_BLOCKED BIT(10)
|
|
||||||
#define SC_OP_RFKILL_HW_BLOCKED BIT(11)
|
|
||||||
#define SC_OP_WAIT_FOR_BEACON BIT(12)
|
#define SC_OP_WAIT_FOR_BEACON BIT(12)
|
||||||
#define SC_OP_LED_ON BIT(13)
|
#define SC_OP_LED_ON BIT(13)
|
||||||
#define SC_OP_SCANNING BIT(14)
|
#define SC_OP_SCANNING BIT(14)
|
||||||
|
@ -411,6 +411,7 @@ void ath_beacon_tasklet(unsigned long data)
|
|||||||
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
|
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
|
||||||
DPRINTF(sc, ATH_DBG_BEACON,
|
DPRINTF(sc, ATH_DBG_BEACON,
|
||||||
"beacon is officially stuck\n");
|
"beacon is officially stuck\n");
|
||||||
|
sc->sc_flags |= SC_OP_TSF_RESET;
|
||||||
ath_reset(sc, false);
|
ath_reset(sc, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,6 +674,14 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
|
|||||||
|
|
||||||
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It looks like mac80211 may end up using beacon interval of zero in
|
||||||
|
* some cases (at least for mesh point). Avoid getting into an
|
||||||
|
* infinite loop by using a bit safer value instead..
|
||||||
|
*/
|
||||||
|
if (intval == 0)
|
||||||
|
intval = 100;
|
||||||
|
|
||||||
/* Pull nexttbtt forward to reflect the current TSF */
|
/* Pull nexttbtt forward to reflect the current TSF */
|
||||||
|
|
||||||
nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
|
nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
|
||||||
|
@ -44,6 +44,44 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t read_file_debug(struct file *file, char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct ath_softc *sc = file->private_data;
|
||||||
|
char buf[32];
|
||||||
|
unsigned int len;
|
||||||
|
|
||||||
|
len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.debug_mask);
|
||||||
|
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct ath_softc *sc = file->private_data;
|
||||||
|
unsigned long mask;
|
||||||
|
char buf[32];
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
|
len = min(count, sizeof(buf) - 1);
|
||||||
|
if (copy_from_user(buf, user_buf, len))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
buf[len] = '\0';
|
||||||
|
if (strict_strtoul(buf, 0, &mask))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
sc->debug.debug_mask = mask;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations fops_debug = {
|
||||||
|
.read = read_file_debug,
|
||||||
|
.write = write_file_debug,
|
||||||
|
.open = ath9k_debugfs_open,
|
||||||
|
.owner = THIS_MODULE
|
||||||
|
};
|
||||||
|
|
||||||
static ssize_t read_file_dma(struct file *file, char __user *user_buf,
|
static ssize_t read_file_dma(struct file *file, char __user *user_buf,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
@ -224,111 +262,66 @@ static const struct file_operations fops_interrupt = {
|
|||||||
.owner = THIS_MODULE
|
.owner = THIS_MODULE
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ath_debug_stat_11n_rc(struct ath_softc *sc, struct sk_buff *skb)
|
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
|
||||||
{
|
|
||||||
struct ath_tx_info_priv *tx_info_priv = NULL;
|
|
||||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
|
||||||
struct ieee80211_tx_rate *rates = tx_info->status.rates;
|
|
||||||
int final_ts_idx, idx;
|
|
||||||
|
|
||||||
tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
|
||||||
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
|
||||||
idx = sc->cur_rate_table->info[rates[final_ts_idx].idx].dot11rate;
|
|
||||||
|
|
||||||
sc->debug.stats.n_rcstats[idx].success++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ath_debug_stat_legacy_rc(struct ath_softc *sc, struct sk_buff *skb)
|
|
||||||
{
|
{
|
||||||
struct ath_tx_info_priv *tx_info_priv = NULL;
|
struct ath_tx_info_priv *tx_info_priv = NULL;
|
||||||
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
||||||
struct ieee80211_tx_rate *rates = tx_info->status.rates;
|
struct ieee80211_tx_rate *rates = tx_info->status.rates;
|
||||||
int final_ts_idx, idx;
|
int final_ts_idx, idx;
|
||||||
|
struct ath_rc_stats *stats;
|
||||||
|
|
||||||
tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
|
||||||
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
final_ts_idx = tx_info_priv->tx.ts_rateindex;
|
||||||
idx = rates[final_ts_idx].idx;
|
idx = rates[final_ts_idx].idx;
|
||||||
|
stats = &sc->debug.stats.rcstats[idx];
|
||||||
sc->debug.stats.legacy_rcstats[idx].success++;
|
stats->success++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
if (conf_is_ht(&sc->hw->conf))
|
|
||||||
ath_debug_stat_11n_rc(sc, skb);
|
|
||||||
else
|
|
||||||
ath_debug_stat_legacy_rc(sc, skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: legacy rates, later on .. */
|
|
||||||
void ath_debug_stat_retries(struct ath_softc *sc, int rix,
|
void ath_debug_stat_retries(struct ath_softc *sc, int rix,
|
||||||
int xretries, int retries, u8 per)
|
int xretries, int retries, u8 per)
|
||||||
{
|
{
|
||||||
if (conf_is_ht(&sc->hw->conf)) {
|
struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix];
|
||||||
int idx = sc->cur_rate_table->info[rix].dot11rate;
|
|
||||||
|
|
||||||
sc->debug.stats.n_rcstats[idx].xretries += xretries;
|
stats->xretries += xretries;
|
||||||
sc->debug.stats.n_rcstats[idx].retries += retries;
|
stats->retries += retries;
|
||||||
sc->debug.stats.n_rcstats[idx].per = per;
|
stats->per = per;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ath_read_file_stat_11n_rc(struct file *file,
|
|
||||||
char __user *user_buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
struct ath_softc *sc = file->private_data;
|
|
||||||
char buf[1024];
|
|
||||||
unsigned int len = 0;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success",
|
|
||||||
"Retries", "XRetries", "PER");
|
|
||||||
|
|
||||||
for (i = 0; i <= 15; i++) {
|
|
||||||
len += snprintf(buf + len, sizeof(buf) - len,
|
|
||||||
"%5s%3d: %8u %8u %8u %8u\n", "MCS", i,
|
|
||||||
sc->debug.stats.n_rcstats[i].success,
|
|
||||||
sc->debug.stats.n_rcstats[i].retries,
|
|
||||||
sc->debug.stats.n_rcstats[i].xretries,
|
|
||||||
sc->debug.stats.n_rcstats[i].per);
|
|
||||||
}
|
|
||||||
|
|
||||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t ath_read_file_stat_legacy_rc(struct file *file,
|
|
||||||
char __user *user_buf,
|
|
||||||
size_t count, loff_t *ppos)
|
|
||||||
{
|
|
||||||
struct ath_softc *sc = file->private_data;
|
|
||||||
char buf[512];
|
|
||||||
unsigned int len = 0;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
len += sprintf(buf, "%7s %13s\n\n", "Rate", "Success");
|
|
||||||
|
|
||||||
for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
|
|
||||||
len += snprintf(buf + len, sizeof(buf) - len, "%5u: %12u\n",
|
|
||||||
sc->cur_rate_table->info[i].ratekbps / 1000,
|
|
||||||
sc->debug.stats.legacy_rcstats[i].success);
|
|
||||||
}
|
|
||||||
|
|
||||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
|
static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct ath_softc *sc = file->private_data;
|
struct ath_softc *sc = file->private_data;
|
||||||
|
char *buf;
|
||||||
|
unsigned int len = 0, max;
|
||||||
|
int i = 0;
|
||||||
|
ssize_t retval;
|
||||||
|
|
||||||
if (sc->cur_rate_table == NULL)
|
if (sc->cur_rate_table == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (conf_is_ht(&sc->hw->conf))
|
max = 80 + sc->cur_rate_table->rate_cnt * 64;
|
||||||
return ath_read_file_stat_11n_rc(file, user_buf, count, ppos);
|
buf = kmalloc(max + 1, GFP_KERNEL);
|
||||||
else
|
if (buf == NULL)
|
||||||
return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos);
|
return 0;
|
||||||
|
buf[max] = 0;
|
||||||
|
|
||||||
|
len += sprintf(buf, "%5s %15s %8s %9s %3s\n\n", "Rate", "Success",
|
||||||
|
"Retries", "XRetries", "PER");
|
||||||
|
|
||||||
|
for (i = 0; i < sc->cur_rate_table->rate_cnt; i++) {
|
||||||
|
u32 ratekbps = sc->cur_rate_table->info[i].ratekbps;
|
||||||
|
struct ath_rc_stats *stats = &sc->debug.stats.rcstats[i];
|
||||||
|
|
||||||
|
len += snprintf(buf + len, max - len,
|
||||||
|
"%3u.%d: %8u %8u %8u %8u\n", ratekbps / 1000,
|
||||||
|
(ratekbps % 1000) / 100, stats->success,
|
||||||
|
stats->retries, stats->xretries,
|
||||||
|
stats->per);
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||||
|
kfree(buf);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations fops_rcstat = {
|
static const struct file_operations fops_rcstat = {
|
||||||
@ -506,6 +499,11 @@ int ath9k_init_debug(struct ath_softc *sc)
|
|||||||
if (!sc->debug.debugfs_phy)
|
if (!sc->debug.debugfs_phy)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
sc->debug.debugfs_debug = debugfs_create_file("debug",
|
||||||
|
S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc, &fops_debug);
|
||||||
|
if (!sc->debug.debugfs_debug)
|
||||||
|
goto err;
|
||||||
|
|
||||||
sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
|
sc->debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO,
|
||||||
sc->debug.debugfs_phy, sc, &fops_dma);
|
sc->debug.debugfs_phy, sc, &fops_dma);
|
||||||
if (!sc->debug.debugfs_dma)
|
if (!sc->debug.debugfs_dma)
|
||||||
@ -543,6 +541,7 @@ void ath9k_exit_debug(struct ath_softc *sc)
|
|||||||
debugfs_remove(sc->debug.debugfs_rcstat);
|
debugfs_remove(sc->debug.debugfs_rcstat);
|
||||||
debugfs_remove(sc->debug.debugfs_interrupt);
|
debugfs_remove(sc->debug.debugfs_interrupt);
|
||||||
debugfs_remove(sc->debug.debugfs_dma);
|
debugfs_remove(sc->debug.debugfs_dma);
|
||||||
|
debugfs_remove(sc->debug.debugfs_debug);
|
||||||
debugfs_remove(sc->debug.debugfs_phy);
|
debugfs_remove(sc->debug.debugfs_phy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,11 +80,7 @@ struct ath_interrupt_stats {
|
|||||||
u32 dtim;
|
u32 dtim;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath_legacy_rc_stats {
|
struct ath_rc_stats {
|
||||||
u32 success;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ath_11n_rc_stats {
|
|
||||||
u32 success;
|
u32 success;
|
||||||
u32 retries;
|
u32 retries;
|
||||||
u32 xretries;
|
u32 xretries;
|
||||||
@ -93,13 +89,13 @@ struct ath_11n_rc_stats {
|
|||||||
|
|
||||||
struct ath_stats {
|
struct ath_stats {
|
||||||
struct ath_interrupt_stats istats;
|
struct ath_interrupt_stats istats;
|
||||||
struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */
|
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
|
||||||
struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath9k_debug {
|
struct ath9k_debug {
|
||||||
int debug_mask;
|
int debug_mask;
|
||||||
struct dentry *debugfs_phy;
|
struct dentry *debugfs_phy;
|
||||||
|
struct dentry *debugfs_debug;
|
||||||
struct dentry *debugfs_dma;
|
struct dentry *debugfs_dma;
|
||||||
struct dentry *debugfs_interrupt;
|
struct dentry *debugfs_interrupt;
|
||||||
struct dentry *debugfs_rcstat;
|
struct dentry *debugfs_rcstat;
|
||||||
|
@ -1192,120 +1192,69 @@ static bool ath_is_rfkill_set(struct ath_softc *sc)
|
|||||||
ah->rfkill_polarity;
|
ah->rfkill_polarity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* h/w rfkill poll function */
|
/* s/w rfkill handlers */
|
||||||
static void ath_rfkill_poll(struct work_struct *work)
|
static int ath_rfkill_set_block(void *data, bool blocked)
|
||||||
{
|
|
||||||
struct ath_softc *sc = container_of(work, struct ath_softc,
|
|
||||||
rf_kill.rfkill_poll.work);
|
|
||||||
bool radio_on;
|
|
||||||
|
|
||||||
if (sc->sc_flags & SC_OP_INVALID)
|
|
||||||
return;
|
|
||||||
|
|
||||||
radio_on = !ath_is_rfkill_set(sc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* enable/disable radio only when there is a
|
|
||||||
* state change in RF switch
|
|
||||||
*/
|
|
||||||
if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) {
|
|
||||||
enum rfkill_state state;
|
|
||||||
|
|
||||||
if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) {
|
|
||||||
state = radio_on ? RFKILL_STATE_SOFT_BLOCKED
|
|
||||||
: RFKILL_STATE_HARD_BLOCKED;
|
|
||||||
} else if (radio_on) {
|
|
||||||
ath_radio_enable(sc);
|
|
||||||
state = RFKILL_STATE_UNBLOCKED;
|
|
||||||
} else {
|
|
||||||
ath_radio_disable(sc);
|
|
||||||
state = RFKILL_STATE_HARD_BLOCKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == RFKILL_STATE_HARD_BLOCKED)
|
|
||||||
sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED;
|
|
||||||
else
|
|
||||||
sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED;
|
|
||||||
|
|
||||||
rfkill_force_state(sc->rf_kill.rfkill, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll,
|
|
||||||
msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* s/w rfkill handler */
|
|
||||||
static int ath_sw_toggle_radio(void *data, enum rfkill_state state)
|
|
||||||
{
|
{
|
||||||
struct ath_softc *sc = data;
|
struct ath_softc *sc = data;
|
||||||
|
|
||||||
switch (state) {
|
if (blocked)
|
||||||
case RFKILL_STATE_SOFT_BLOCKED:
|
ath_radio_disable(sc);
|
||||||
if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED |
|
else
|
||||||
SC_OP_RFKILL_SW_BLOCKED)))
|
ath_radio_enable(sc);
|
||||||
ath_radio_disable(sc);
|
|
||||||
sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED;
|
return 0;
|
||||||
return 0;
|
}
|
||||||
case RFKILL_STATE_UNBLOCKED:
|
|
||||||
if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) {
|
static void ath_rfkill_poll_state(struct rfkill *rfkill, void *data)
|
||||||
sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED;
|
{
|
||||||
if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) {
|
struct ath_softc *sc = data;
|
||||||
DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the"
|
bool blocked = !!ath_is_rfkill_set(sc);
|
||||||
"radio as it is disabled by h/w\n");
|
|
||||||
return -EPERM;
|
if (rfkill_set_hw_state(rfkill, blocked))
|
||||||
}
|
ath_radio_disable(sc);
|
||||||
ath_radio_enable(sc);
|
else
|
||||||
}
|
ath_radio_enable(sc);
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init s/w rfkill */
|
/* Init s/w rfkill */
|
||||||
static int ath_init_sw_rfkill(struct ath_softc *sc)
|
static int ath_init_sw_rfkill(struct ath_softc *sc)
|
||||||
{
|
{
|
||||||
sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy),
|
sc->rf_kill.ops.set_block = ath_rfkill_set_block;
|
||||||
RFKILL_TYPE_WLAN);
|
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
||||||
|
sc->rf_kill.ops.poll = ath_rfkill_poll_state;
|
||||||
|
|
||||||
|
snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
|
||||||
|
"ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy));
|
||||||
|
|
||||||
|
sc->rf_kill.rfkill = rfkill_alloc(sc->rf_kill.rfkill_name,
|
||||||
|
wiphy_dev(sc->hw->wiphy),
|
||||||
|
RFKILL_TYPE_WLAN,
|
||||||
|
&sc->rf_kill.ops, sc);
|
||||||
if (!sc->rf_kill.rfkill) {
|
if (!sc->rf_kill.rfkill) {
|
||||||
DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
|
DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
|
|
||||||
"ath9k-%s::rfkill", wiphy_name(sc->hw->wiphy));
|
|
||||||
sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name;
|
|
||||||
sc->rf_kill.rfkill->data = sc;
|
|
||||||
sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
|
|
||||||
sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deinitialize rfkill */
|
/* Deinitialize rfkill */
|
||||||
static void ath_deinit_rfkill(struct ath_softc *sc)
|
static void ath_deinit_rfkill(struct ath_softc *sc)
|
||||||
{
|
{
|
||||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
|
||||||
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
|
|
||||||
|
|
||||||
if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
|
if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
|
||||||
rfkill_unregister(sc->rf_kill.rfkill);
|
rfkill_unregister(sc->rf_kill.rfkill);
|
||||||
|
rfkill_destroy(sc->rf_kill.rfkill);
|
||||||
sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED;
|
sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED;
|
||||||
sc->rf_kill.rfkill = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath_start_rfkill_poll(struct ath_softc *sc)
|
static int ath_start_rfkill_poll(struct ath_softc *sc)
|
||||||
{
|
{
|
||||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
|
||||||
queue_delayed_work(sc->hw->workqueue,
|
|
||||||
&sc->rf_kill.rfkill_poll, 0);
|
|
||||||
|
|
||||||
if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
|
if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
|
||||||
if (rfkill_register(sc->rf_kill.rfkill)) {
|
if (rfkill_register(sc->rf_kill.rfkill)) {
|
||||||
DPRINTF(sc, ATH_DBG_FATAL,
|
DPRINTF(sc, ATH_DBG_FATAL,
|
||||||
"Unable to register rfkill\n");
|
"Unable to register rfkill\n");
|
||||||
rfkill_free(sc->rf_kill.rfkill);
|
rfkill_destroy(sc->rf_kill.rfkill);
|
||||||
|
|
||||||
/* Deinitialize the device */
|
/* Deinitialize the device */
|
||||||
ath_cleanup(sc);
|
ath_cleanup(sc);
|
||||||
@ -1678,10 +1627,6 @@ int ath_attach(u16 devid, struct ath_softc *sc)
|
|||||||
goto error_attach;
|
goto error_attach;
|
||||||
|
|
||||||
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
|
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
|
||||||
/* Initialze h/w Rfkill */
|
|
||||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
|
||||||
INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
|
|
||||||
|
|
||||||
/* Initialize s/w rfkill */
|
/* Initialize s/w rfkill */
|
||||||
error = ath_init_sw_rfkill(sc);
|
error = ath_init_sw_rfkill(sc);
|
||||||
if (error)
|
if (error)
|
||||||
@ -2214,10 +2159,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
|
|||||||
} else
|
} else
|
||||||
sc->rx.rxlink = NULL;
|
sc->rx.rxlink = NULL;
|
||||||
|
|
||||||
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
|
rfkill_pause_polling(sc->rf_kill.rfkill);
|
||||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
|
||||||
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
|
|
||||||
#endif
|
|
||||||
/* disable HAL and put h/w to sleep */
|
/* disable HAL and put h/w to sleep */
|
||||||
ath9k_hw_disable(sc->sc_ah);
|
ath9k_hw_disable(sc->sc_ah);
|
||||||
ath9k_hw_configpcipowersave(sc->sc_ah, 1);
|
ath9k_hw_configpcipowersave(sc->sc_ah, 1);
|
||||||
|
@ -227,11 +227,6 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||||||
|
|
||||||
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
|
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
|
||||||
|
|
||||||
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
|
|
||||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
|
||||||
cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pci_save_state(pdev);
|
pci_save_state(pdev);
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
pci_set_power_state(pdev, PCI_D3hot);
|
pci_set_power_state(pdev, PCI_D3hot);
|
||||||
@ -256,16 +251,6 @@ static int ath_pci_resume(struct pci_dev *pdev)
|
|||||||
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
|
||||||
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
|
ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
|
||||||
|
|
||||||
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
|
|
||||||
/*
|
|
||||||
* check the h/w rfkill state on resume
|
|
||||||
* and start the rfkill poll timer
|
|
||||||
*/
|
|
||||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
|
|
||||||
queue_delayed_work(sc->hw->workqueue,
|
|
||||||
&sc->rf_kill.rfkill_poll, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,11 +366,17 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
|
|||||||
if (rd & COUNTRY_ERD_FLAG) {
|
if (rd & COUNTRY_ERD_FLAG) {
|
||||||
/* EEPROM value is a country code */
|
/* EEPROM value is a country code */
|
||||||
u16 cc = rd & ~COUNTRY_ERD_FLAG;
|
u16 cc = rd & ~COUNTRY_ERD_FLAG;
|
||||||
|
printk(KERN_DEBUG
|
||||||
|
"ath: EEPROM indicates we should expect "
|
||||||
|
"a country code\n");
|
||||||
for (i = 0; i < ARRAY_SIZE(allCountries); i++)
|
for (i = 0; i < ARRAY_SIZE(allCountries); i++)
|
||||||
if (allCountries[i].countryCode == cc)
|
if (allCountries[i].countryCode == cc)
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
/* EEPROM value is a regpair value */
|
/* EEPROM value is a regpair value */
|
||||||
|
if (rd != CTRY_DEFAULT)
|
||||||
|
printk(KERN_DEBUG "ath: EEPROM indicates we "
|
||||||
|
"should expect a direct regpair map\n");
|
||||||
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
|
for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
|
||||||
if (regDomainPairs[i].regDmnEnum == rd)
|
if (regDomainPairs[i].regDmnEnum == rd)
|
||||||
return true;
|
return true;
|
||||||
@ -477,6 +483,11 @@ ath_regd_init(struct ath_regulatory *reg,
|
|||||||
struct country_code_to_enum_rd *country = NULL;
|
struct country_code_to_enum_rd *country = NULL;
|
||||||
u16 regdmn;
|
u16 regdmn;
|
||||||
|
|
||||||
|
if (!reg)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd);
|
||||||
|
|
||||||
if (!ath_regd_is_eeprom_valid(reg)) {
|
if (!ath_regd_is_eeprom_valid(reg)) {
|
||||||
printk(KERN_ERR "ath: Invalid EEPROM contents\n");
|
printk(KERN_ERR "ath: Invalid EEPROM contents\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -486,20 +497,30 @@ ath_regd_init(struct ath_regulatory *reg,
|
|||||||
reg->country_code = ath_regd_get_default_country(regdmn);
|
reg->country_code = ath_regd_get_default_country(regdmn);
|
||||||
|
|
||||||
if (reg->country_code == CTRY_DEFAULT &&
|
if (reg->country_code == CTRY_DEFAULT &&
|
||||||
regdmn == CTRY_DEFAULT)
|
regdmn == CTRY_DEFAULT) {
|
||||||
|
printk(KERN_DEBUG "ath: EEPROM indicates default "
|
||||||
|
"country code should be used\n");
|
||||||
reg->country_code = CTRY_UNITED_STATES;
|
reg->country_code = CTRY_UNITED_STATES;
|
||||||
|
}
|
||||||
|
|
||||||
if (reg->country_code == CTRY_DEFAULT) {
|
if (reg->country_code == CTRY_DEFAULT) {
|
||||||
country = NULL;
|
country = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
printk(KERN_DEBUG "ath: doing EEPROM country->regdmn "
|
||||||
|
"map search\n");
|
||||||
country = ath_regd_find_country(reg->country_code);
|
country = ath_regd_find_country(reg->country_code);
|
||||||
if (country == NULL) {
|
if (country == NULL) {
|
||||||
printk(KERN_DEBUG
|
printk(KERN_DEBUG
|
||||||
"ath: Country is NULL!!!!, cc= %d\n",
|
"ath: no valid country maps found for "
|
||||||
|
"country code: 0x%0x\n",
|
||||||
reg->country_code);
|
reg->country_code);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
} else
|
} else {
|
||||||
regdmn = country->regDmnEnum;
|
regdmn = country->regDmnEnum;
|
||||||
|
printk(KERN_DEBUG "ath: country maps to "
|
||||||
|
"regdmn code: 0x%0x\n",
|
||||||
|
regdmn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reg->regpair = ath_get_regpair(regdmn);
|
reg->regpair = ath_get_regpair(regdmn);
|
||||||
@ -523,7 +544,7 @@ ath_regd_init(struct ath_regulatory *reg,
|
|||||||
|
|
||||||
printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
|
printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
|
||||||
reg->alpha2[0], reg->alpha2[1]);
|
reg->alpha2[0], reg->alpha2[1]);
|
||||||
printk(KERN_DEBUG "ath: Regpair detected: 0x%0x\n",
|
printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
|
||||||
reg->regpair->regDmnEnum);
|
reg->regpair->regDmnEnum);
|
||||||
|
|
||||||
ath_regd_init_wiphy(reg, wiphy, reg_notifier);
|
ath_regd_init_wiphy(reg, wiphy, reg_notifier);
|
||||||
|
@ -102,7 +102,7 @@ config B43_LEDS
|
|||||||
# if it's possible.
|
# if it's possible.
|
||||||
config B43_RFKILL
|
config B43_RFKILL
|
||||||
bool
|
bool
|
||||||
depends on B43 && (RFKILL = y || RFKILL = B43) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43)
|
depends on B43 && (RFKILL = y || RFKILL = B43)
|
||||||
default y
|
default y
|
||||||
|
|
||||||
# This config option automatically enables b43 HW-RNG support,
|
# This config option automatically enables b43 HW-RNG support,
|
||||||
|
@ -87,7 +87,7 @@ static void b43_led_brightness_set(struct led_classdev *led_dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
|
static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
|
||||||
const char *name, char *default_trigger,
|
const char *name, const char *default_trigger,
|
||||||
u8 led_index, bool activelow)
|
u8 led_index, bool activelow)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -3470,7 +3470,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
|
|
||||||
if (!!conf->radio_enabled != phy->radio_on) {
|
if (!!conf->radio_enabled != phy->radio_on) {
|
||||||
if (conf->radio_enabled) {
|
if (conf->radio_enabled) {
|
||||||
b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
|
b43_software_rfkill(dev, false);
|
||||||
b43info(dev->wl, "Radio turned on by software\n");
|
b43info(dev->wl, "Radio turned on by software\n");
|
||||||
if (!dev->radio_hw_enable) {
|
if (!dev->radio_hw_enable) {
|
||||||
b43info(dev->wl, "The hardware RF-kill button "
|
b43info(dev->wl, "The hardware RF-kill button "
|
||||||
@ -3478,7 +3478,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
"Press the button to turn it on.\n");
|
"Press the button to turn it on.\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
|
b43_software_rfkill(dev, true);
|
||||||
b43info(dev->wl, "Radio turned off by software\n");
|
b43info(dev->wl, "Radio turned off by software\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,11 +480,11 @@ static bool b43_aphy_op_supports_hwpctl(struct b43_wldev *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void b43_aphy_op_software_rfkill(struct b43_wldev *dev,
|
static void b43_aphy_op_software_rfkill(struct b43_wldev *dev,
|
||||||
enum rfkill_state state)
|
bool blocked)
|
||||||
{
|
{
|
||||||
struct b43_phy *phy = &dev->phy;
|
struct b43_phy *phy = &dev->phy;
|
||||||
|
|
||||||
if (state == RFKILL_STATE_UNBLOCKED) {
|
if (!blocked) {
|
||||||
if (phy->radio_on)
|
if (phy->radio_on)
|
||||||
return;
|
return;
|
||||||
b43_radio_write16(dev, 0x0004, 0x00C0);
|
b43_radio_write16(dev, 0x0004, 0x00C0);
|
||||||
|
@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev)
|
|||||||
|
|
||||||
phy->channel = ops->get_default_chan(dev);
|
phy->channel = ops->get_default_chan(dev);
|
||||||
|
|
||||||
ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
|
ops->software_rfkill(dev, false);
|
||||||
err = ops->init(dev);
|
err = ops->init(dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
b43err(dev->wl, "PHY init failed\n");
|
b43err(dev->wl, "PHY init failed\n");
|
||||||
@ -104,7 +104,7 @@ err_phy_exit:
|
|||||||
if (ops->exit)
|
if (ops->exit)
|
||||||
ops->exit(dev);
|
ops->exit(dev);
|
||||||
err_block_rf:
|
err_block_rf:
|
||||||
ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
|
ops->software_rfkill(dev, true);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ void b43_phy_exit(struct b43_wldev *dev)
|
|||||||
{
|
{
|
||||||
const struct b43_phy_operations *ops = dev->phy.ops;
|
const struct b43_phy_operations *ops = dev->phy.ops;
|
||||||
|
|
||||||
ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
|
ops->software_rfkill(dev, true);
|
||||||
if (ops->exit)
|
if (ops->exit)
|
||||||
ops->exit(dev);
|
ops->exit(dev);
|
||||||
}
|
}
|
||||||
@ -295,18 +295,13 @@ err_restore_cookie:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state)
|
void b43_software_rfkill(struct b43_wldev *dev, bool blocked)
|
||||||
{
|
{
|
||||||
struct b43_phy *phy = &dev->phy;
|
struct b43_phy *phy = &dev->phy;
|
||||||
|
|
||||||
if (state == RFKILL_STATE_HARD_BLOCKED) {
|
|
||||||
/* We cannot hardware-block the device */
|
|
||||||
state = RFKILL_STATE_SOFT_BLOCKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
b43_mac_suspend(dev);
|
b43_mac_suspend(dev);
|
||||||
phy->ops->software_rfkill(dev, state);
|
phy->ops->software_rfkill(dev, blocked);
|
||||||
phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
|
phy->radio_on = !blocked;
|
||||||
b43_mac_enable(dev);
|
b43_mac_enable(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ struct b43_phy_operations {
|
|||||||
|
|
||||||
/* Radio */
|
/* Radio */
|
||||||
bool (*supports_hwpctl)(struct b43_wldev *dev);
|
bool (*supports_hwpctl)(struct b43_wldev *dev);
|
||||||
void (*software_rfkill)(struct b43_wldev *dev, enum rfkill_state state);
|
void (*software_rfkill)(struct b43_wldev *dev, bool blocked);
|
||||||
void (*switch_analog)(struct b43_wldev *dev, bool on);
|
void (*switch_analog)(struct b43_wldev *dev, bool on);
|
||||||
int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel);
|
int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel);
|
||||||
unsigned int (*get_default_chan)(struct b43_wldev *dev);
|
unsigned int (*get_default_chan)(struct b43_wldev *dev);
|
||||||
@ -364,7 +364,7 @@ int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel);
|
|||||||
/**
|
/**
|
||||||
* b43_software_rfkill - Turn the radio ON or OFF in software.
|
* b43_software_rfkill - Turn the radio ON or OFF in software.
|
||||||
*/
|
*/
|
||||||
void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state);
|
void b43_software_rfkill(struct b43_wldev *dev, bool blocked);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* b43_phy_txpower_check - Check TX power output.
|
* b43_phy_txpower_check - Check TX power output.
|
||||||
|
@ -2592,7 +2592,7 @@ static bool b43_gphy_op_supports_hwpctl(struct b43_wldev *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
|
static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
|
||||||
enum rfkill_state state)
|
bool blocked)
|
||||||
{
|
{
|
||||||
struct b43_phy *phy = &dev->phy;
|
struct b43_phy *phy = &dev->phy;
|
||||||
struct b43_phy_g *gphy = phy->g;
|
struct b43_phy_g *gphy = phy->g;
|
||||||
@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
|
|||||||
|
|
||||||
might_sleep();
|
might_sleep();
|
||||||
|
|
||||||
if (state == RFKILL_STATE_UNBLOCKED) {
|
if (!blocked) {
|
||||||
/* Turn radio ON */
|
/* Turn radio ON */
|
||||||
if (phy->radio_on)
|
if (phy->radio_on)
|
||||||
return;
|
return;
|
||||||
|
@ -488,7 +488,7 @@ static void b43_lpphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
|
static void b43_lpphy_op_software_rfkill(struct b43_wldev *dev,
|
||||||
enum rfkill_state state)
|
bool blocked)
|
||||||
{
|
{
|
||||||
//TODO
|
//TODO
|
||||||
}
|
}
|
||||||
|
@ -579,7 +579,7 @@ static void b43_nphy_op_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
|
static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
|
||||||
enum rfkill_state state)
|
bool blocked)
|
||||||
{//TODO
|
{//TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,12 +45,11 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* The poll callback for the hardware button. */
|
/* The poll callback for the hardware button. */
|
||||||
static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
|
static void b43_rfkill_poll(struct rfkill *rfkill, void *data)
|
||||||
{
|
{
|
||||||
struct b43_wldev *dev = poll_dev->private;
|
struct b43_wldev *dev = data;
|
||||||
struct b43_wl *wl = dev->wl;
|
struct b43_wl *wl = dev->wl;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool report_change = 0;
|
|
||||||
|
|
||||||
mutex_lock(&wl->mutex);
|
mutex_lock(&wl->mutex);
|
||||||
if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) {
|
if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) {
|
||||||
@ -60,68 +59,55 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
|
|||||||
enabled = b43_is_hw_radio_enabled(dev);
|
enabled = b43_is_hw_radio_enabled(dev);
|
||||||
if (unlikely(enabled != dev->radio_hw_enable)) {
|
if (unlikely(enabled != dev->radio_hw_enable)) {
|
||||||
dev->radio_hw_enable = enabled;
|
dev->radio_hw_enable = enabled;
|
||||||
report_change = 1;
|
|
||||||
b43info(wl, "Radio hardware status changed to %s\n",
|
b43info(wl, "Radio hardware status changed to %s\n",
|
||||||
enabled ? "ENABLED" : "DISABLED");
|
enabled ? "ENABLED" : "DISABLED");
|
||||||
|
enabled = !rfkill_set_hw_state(rfkill, !enabled);
|
||||||
|
if (enabled != dev->phy.radio_on)
|
||||||
|
b43_software_rfkill(dev, !enabled);
|
||||||
}
|
}
|
||||||
mutex_unlock(&wl->mutex);
|
mutex_unlock(&wl->mutex);
|
||||||
|
|
||||||
/* send the radio switch event to the system - note both a key press
|
|
||||||
* and a release are required */
|
|
||||||
if (unlikely(report_change)) {
|
|
||||||
input_report_key(poll_dev->input, KEY_WLAN, 1);
|
|
||||||
input_report_key(poll_dev->input, KEY_WLAN, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called when the RFKILL toggled in software. */
|
/* Called when the RFKILL toggled in software. */
|
||||||
static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
|
static int b43_rfkill_soft_set(void *data, bool blocked)
|
||||||
{
|
{
|
||||||
struct b43_wldev *dev = data;
|
struct b43_wldev *dev = data;
|
||||||
struct b43_wl *wl = dev->wl;
|
struct b43_wl *wl = dev->wl;
|
||||||
int err = -EBUSY;
|
int err = -EINVAL;
|
||||||
|
|
||||||
if (!wl->rfkill.registered)
|
if (WARN_ON(!wl->rfkill.registered))
|
||||||
return 0;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&wl->mutex);
|
mutex_lock(&wl->mutex);
|
||||||
|
|
||||||
if (b43_status(dev) < B43_STAT_INITIALIZED)
|
if (b43_status(dev) < B43_STAT_INITIALIZED)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
|
if (!dev->radio_hw_enable)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
if (!blocked != dev->phy.radio_on)
|
||||||
|
b43_software_rfkill(dev, blocked);
|
||||||
err = 0;
|
err = 0;
|
||||||
switch (state) {
|
|
||||||
case RFKILL_STATE_UNBLOCKED:
|
|
||||||
if (!dev->radio_hw_enable) {
|
|
||||||
/* No luck. We can't toggle the hardware RF-kill
|
|
||||||
* button from software. */
|
|
||||||
err = -EBUSY;
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
if (!dev->phy.radio_on)
|
|
||||||
b43_software_rfkill(dev, state);
|
|
||||||
break;
|
|
||||||
case RFKILL_STATE_SOFT_BLOCKED:
|
|
||||||
if (dev->phy.radio_on)
|
|
||||||
b43_software_rfkill(dev, state);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
b43warn(wl, "Received unexpected rfkill state %d.\n", state);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&wl->mutex);
|
mutex_unlock(&wl->mutex);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *b43_rfkill_led_name(struct b43_wldev *dev)
|
const char *b43_rfkill_led_name(struct b43_wldev *dev)
|
||||||
{
|
{
|
||||||
struct b43_rfkill *rfk = &(dev->wl->rfkill);
|
struct b43_rfkill *rfk = &(dev->wl->rfkill);
|
||||||
|
|
||||||
if (!rfk->registered)
|
if (!rfk->registered)
|
||||||
return NULL;
|
return NULL;
|
||||||
return rfkill_get_led_name(rfk->rfkill);
|
return rfkill_get_led_trigger_name(rfk->rfkill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct rfkill_ops b43_rfkill_ops = {
|
||||||
|
.set_block = b43_rfkill_soft_set,
|
||||||
|
.poll = b43_rfkill_poll,
|
||||||
|
};
|
||||||
|
|
||||||
void b43_rfkill_init(struct b43_wldev *dev)
|
void b43_rfkill_init(struct b43_wldev *dev)
|
||||||
{
|
{
|
||||||
struct b43_wl *wl = dev->wl;
|
struct b43_wl *wl = dev->wl;
|
||||||
@ -130,65 +116,26 @@ void b43_rfkill_init(struct b43_wldev *dev)
|
|||||||
|
|
||||||
rfk->registered = 0;
|
rfk->registered = 0;
|
||||||
|
|
||||||
rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
|
|
||||||
if (!rfk->rfkill)
|
|
||||||
goto out_error;
|
|
||||||
snprintf(rfk->name, sizeof(rfk->name),
|
snprintf(rfk->name, sizeof(rfk->name),
|
||||||
"b43-%s", wiphy_name(wl->hw->wiphy));
|
"b43-%s", wiphy_name(wl->hw->wiphy));
|
||||||
rfk->rfkill->name = rfk->name;
|
|
||||||
rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
|
|
||||||
rfk->rfkill->data = dev;
|
|
||||||
rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle;
|
|
||||||
|
|
||||||
rfk->poll_dev = input_allocate_polled_device();
|
rfk->rfkill = rfkill_alloc(rfk->name,
|
||||||
if (!rfk->poll_dev) {
|
dev->dev->dev,
|
||||||
rfkill_free(rfk->rfkill);
|
RFKILL_TYPE_WLAN,
|
||||||
goto err_freed_rfk;
|
&b43_rfkill_ops, dev);
|
||||||
}
|
if (!rfk->rfkill)
|
||||||
|
goto out_error;
|
||||||
rfk->poll_dev->private = dev;
|
|
||||||
rfk->poll_dev->poll = b43_rfkill_poll;
|
|
||||||
rfk->poll_dev->poll_interval = 1000; /* msecs */
|
|
||||||
|
|
||||||
rfk->poll_dev->input->name = rfk->name;
|
|
||||||
rfk->poll_dev->input->id.bustype = BUS_HOST;
|
|
||||||
rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
|
|
||||||
rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
|
|
||||||
set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
|
|
||||||
|
|
||||||
err = rfkill_register(rfk->rfkill);
|
err = rfkill_register(rfk->rfkill);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_free_polldev;
|
goto err_free;
|
||||||
|
|
||||||
#ifdef CONFIG_RFKILL_INPUT_MODULE
|
|
||||||
/* B43 RF-kill isn't useful without the rfkill-input subsystem.
|
|
||||||
* Try to load the module. */
|
|
||||||
err = request_module("rfkill-input");
|
|
||||||
if (err)
|
|
||||||
b43warn(wl, "Failed to load the rfkill-input module. "
|
|
||||||
"The built-in radio LED will not work.\n");
|
|
||||||
#endif /* CONFIG_RFKILL_INPUT */
|
|
||||||
|
|
||||||
#if !defined(CONFIG_RFKILL_INPUT) && !defined(CONFIG_RFKILL_INPUT_MODULE)
|
|
||||||
b43warn(wl, "The rfkill-input subsystem is not available. "
|
|
||||||
"The built-in radio LED will not work.\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err = input_register_polled_device(rfk->poll_dev);
|
|
||||||
if (err)
|
|
||||||
goto err_unreg_rfk;
|
|
||||||
|
|
||||||
rfk->registered = 1;
|
rfk->registered = 1;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
err_unreg_rfk:
|
err_free:
|
||||||
rfkill_unregister(rfk->rfkill);
|
rfkill_destroy(rfk->rfkill);
|
||||||
err_free_polldev:
|
out_error:
|
||||||
input_free_polled_device(rfk->poll_dev);
|
|
||||||
rfk->poll_dev = NULL;
|
|
||||||
err_freed_rfk:
|
|
||||||
rfk->rfkill = NULL;
|
|
||||||
out_error:
|
|
||||||
rfk->registered = 0;
|
rfk->registered = 0;
|
||||||
b43warn(wl, "RF-kill button init failed\n");
|
b43warn(wl, "RF-kill button init failed\n");
|
||||||
}
|
}
|
||||||
@ -201,9 +148,7 @@ void b43_rfkill_exit(struct b43_wldev *dev)
|
|||||||
return;
|
return;
|
||||||
rfk->registered = 0;
|
rfk->registered = 0;
|
||||||
|
|
||||||
input_unregister_polled_device(rfk->poll_dev);
|
|
||||||
rfkill_unregister(rfk->rfkill);
|
rfkill_unregister(rfk->rfkill);
|
||||||
input_free_polled_device(rfk->poll_dev);
|
rfkill_destroy(rfk->rfkill);
|
||||||
rfk->poll_dev = NULL;
|
|
||||||
rfk->rfkill = NULL;
|
rfk->rfkill = NULL;
|
||||||
}
|
}
|
||||||
|
@ -7,14 +7,11 @@ struct b43_wldev;
|
|||||||
#ifdef CONFIG_B43_RFKILL
|
#ifdef CONFIG_B43_RFKILL
|
||||||
|
|
||||||
#include <linux/rfkill.h>
|
#include <linux/rfkill.h>
|
||||||
#include <linux/input-polldev.h>
|
|
||||||
|
|
||||||
|
|
||||||
struct b43_rfkill {
|
struct b43_rfkill {
|
||||||
/* The RFKILL subsystem data structure */
|
/* The RFKILL subsystem data structure */
|
||||||
struct rfkill *rfkill;
|
struct rfkill *rfkill;
|
||||||
/* The poll device for the RFKILL input button */
|
|
||||||
struct input_polled_dev *poll_dev;
|
|
||||||
/* Did initialization succeed? Used for freeing. */
|
/* Did initialization succeed? Used for freeing. */
|
||||||
bool registered;
|
bool registered;
|
||||||
/* The unique name of this rfkill switch */
|
/* The unique name of this rfkill switch */
|
||||||
@ -26,7 +23,7 @@ struct b43_rfkill {
|
|||||||
void b43_rfkill_init(struct b43_wldev *dev);
|
void b43_rfkill_init(struct b43_wldev *dev);
|
||||||
void b43_rfkill_exit(struct b43_wldev *dev);
|
void b43_rfkill_exit(struct b43_wldev *dev);
|
||||||
|
|
||||||
char * b43_rfkill_led_name(struct b43_wldev *dev);
|
const char *b43_rfkill_led_name(struct b43_wldev *dev);
|
||||||
|
|
||||||
|
|
||||||
#else /* CONFIG_B43_RFKILL */
|
#else /* CONFIG_B43_RFKILL */
|
||||||
|
@ -47,7 +47,7 @@ config B43LEGACY_LEDS
|
|||||||
# if it's possible.
|
# if it's possible.
|
||||||
config B43LEGACY_RFKILL
|
config B43LEGACY_RFKILL
|
||||||
bool
|
bool
|
||||||
depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY)
|
depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY)
|
||||||
default y
|
default y
|
||||||
|
|
||||||
# This config option automatically enables b43 HW-RNG support,
|
# This config option automatically enables b43 HW-RNG support,
|
||||||
|
@ -86,7 +86,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev,
|
|||||||
|
|
||||||
static int b43legacy_register_led(struct b43legacy_wldev *dev,
|
static int b43legacy_register_led(struct b43legacy_wldev *dev,
|
||||||
struct b43legacy_led *led,
|
struct b43legacy_led *led,
|
||||||
const char *name, char *default_trigger,
|
const char *name,
|
||||||
|
const char *default_trigger,
|
||||||
u8 led_index, bool activelow)
|
u8 led_index, bool activelow)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -45,12 +45,11 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* The poll callback for the hardware button. */
|
/* The poll callback for the hardware button. */
|
||||||
static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
|
static void b43legacy_rfkill_poll(struct rfkill *rfkill, void *data)
|
||||||
{
|
{
|
||||||
struct b43legacy_wldev *dev = poll_dev->private;
|
struct b43legacy_wldev *dev = data;
|
||||||
struct b43legacy_wl *wl = dev->wl;
|
struct b43legacy_wl *wl = dev->wl;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
bool report_change = 0;
|
|
||||||
|
|
||||||
mutex_lock(&wl->mutex);
|
mutex_lock(&wl->mutex);
|
||||||
if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) {
|
if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) {
|
||||||
@ -60,71 +59,64 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
|
|||||||
enabled = b43legacy_is_hw_radio_enabled(dev);
|
enabled = b43legacy_is_hw_radio_enabled(dev);
|
||||||
if (unlikely(enabled != dev->radio_hw_enable)) {
|
if (unlikely(enabled != dev->radio_hw_enable)) {
|
||||||
dev->radio_hw_enable = enabled;
|
dev->radio_hw_enable = enabled;
|
||||||
report_change = 1;
|
|
||||||
b43legacyinfo(wl, "Radio hardware status changed to %s\n",
|
b43legacyinfo(wl, "Radio hardware status changed to %s\n",
|
||||||
enabled ? "ENABLED" : "DISABLED");
|
enabled ? "ENABLED" : "DISABLED");
|
||||||
|
enabled = !rfkill_set_hw_state(rfkill, !enabled);
|
||||||
|
if (enabled != dev->phy.radio_on) {
|
||||||
|
if (enabled)
|
||||||
|
b43legacy_radio_turn_on(dev);
|
||||||
|
else
|
||||||
|
b43legacy_radio_turn_off(dev, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&wl->mutex);
|
mutex_unlock(&wl->mutex);
|
||||||
|
|
||||||
/* send the radio switch event to the system - note both a key press
|
|
||||||
* and a release are required */
|
|
||||||
if (unlikely(report_change)) {
|
|
||||||
input_report_key(poll_dev->input, KEY_WLAN, 1);
|
|
||||||
input_report_key(poll_dev->input, KEY_WLAN, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called when the RFKILL toggled in software.
|
/* Called when the RFKILL toggled in software.
|
||||||
* This is called without locking. */
|
* This is called without locking. */
|
||||||
static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
|
static int b43legacy_rfkill_soft_set(void *data, bool blocked)
|
||||||
{
|
{
|
||||||
struct b43legacy_wldev *dev = data;
|
struct b43legacy_wldev *dev = data;
|
||||||
struct b43legacy_wl *wl = dev->wl;
|
struct b43legacy_wl *wl = dev->wl;
|
||||||
int err = -EBUSY;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
if (!wl->rfkill.registered)
|
if (!wl->rfkill.registered)
|
||||||
return 0;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&wl->mutex);
|
mutex_lock(&wl->mutex);
|
||||||
if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
|
if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
err = 0;
|
|
||||||
switch (state) {
|
if (!dev->radio_hw_enable)
|
||||||
case RFKILL_STATE_UNBLOCKED:
|
goto out_unlock;
|
||||||
if (!dev->radio_hw_enable) {
|
|
||||||
/* No luck. We can't toggle the hardware RF-kill
|
if (!blocked != dev->phy.radio_on) {
|
||||||
* button from software. */
|
if (!blocked)
|
||||||
err = -EBUSY;
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
if (!dev->phy.radio_on)
|
|
||||||
b43legacy_radio_turn_on(dev);
|
b43legacy_radio_turn_on(dev);
|
||||||
break;
|
else
|
||||||
case RFKILL_STATE_SOFT_BLOCKED:
|
|
||||||
if (dev->phy.radio_on)
|
|
||||||
b43legacy_radio_turn_off(dev, 0);
|
b43legacy_radio_turn_off(dev, 0);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
b43legacywarn(wl, "Received unexpected rfkill state %d.\n",
|
|
||||||
state);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&wl->mutex);
|
mutex_unlock(&wl->mutex);
|
||||||
|
return ret;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)
|
const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)
|
||||||
{
|
{
|
||||||
struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
|
struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
|
||||||
|
|
||||||
if (!rfk->registered)
|
if (!rfk->registered)
|
||||||
return NULL;
|
return NULL;
|
||||||
return rfkill_get_led_name(rfk->rfkill);
|
return rfkill_get_led_trigger_name(rfk->rfkill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct rfkill_ops b43legacy_rfkill_ops = {
|
||||||
|
.set_block = b43legacy_rfkill_soft_set,
|
||||||
|
.poll = b43legacy_rfkill_poll,
|
||||||
|
};
|
||||||
|
|
||||||
void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
|
void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
|
||||||
{
|
{
|
||||||
struct b43legacy_wl *wl = dev->wl;
|
struct b43legacy_wl *wl = dev->wl;
|
||||||
@ -133,60 +125,25 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
|
|||||||
|
|
||||||
rfk->registered = 0;
|
rfk->registered = 0;
|
||||||
|
|
||||||
rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
|
|
||||||
if (!rfk->rfkill)
|
|
||||||
goto out_error;
|
|
||||||
snprintf(rfk->name, sizeof(rfk->name),
|
snprintf(rfk->name, sizeof(rfk->name),
|
||||||
"b43legacy-%s", wiphy_name(wl->hw->wiphy));
|
"b43legacy-%s", wiphy_name(wl->hw->wiphy));
|
||||||
rfk->rfkill->name = rfk->name;
|
rfk->rfkill = rfkill_alloc(rfk->name,
|
||||||
rfk->rfkill->state = RFKILL_STATE_UNBLOCKED;
|
dev->dev->dev,
|
||||||
rfk->rfkill->data = dev;
|
RFKILL_TYPE_WLAN,
|
||||||
rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle;
|
&b43legacy_rfkill_ops, dev);
|
||||||
|
if (!rfk->rfkill)
|
||||||
rfk->poll_dev = input_allocate_polled_device();
|
goto out_error;
|
||||||
if (!rfk->poll_dev) {
|
|
||||||
rfkill_free(rfk->rfkill);
|
|
||||||
goto err_freed_rfk;
|
|
||||||
}
|
|
||||||
|
|
||||||
rfk->poll_dev->private = dev;
|
|
||||||
rfk->poll_dev->poll = b43legacy_rfkill_poll;
|
|
||||||
rfk->poll_dev->poll_interval = 1000; /* msecs */
|
|
||||||
|
|
||||||
rfk->poll_dev->input->name = rfk->name;
|
|
||||||
rfk->poll_dev->input->id.bustype = BUS_HOST;
|
|
||||||
rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
|
|
||||||
rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
|
|
||||||
set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
|
|
||||||
|
|
||||||
err = rfkill_register(rfk->rfkill);
|
err = rfkill_register(rfk->rfkill);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_free_polldev;
|
goto err_free;
|
||||||
|
|
||||||
#ifdef CONFIG_RFKILL_INPUT_MODULE
|
|
||||||
/* B43legacy RF-kill isn't useful without the rfkill-input subsystem.
|
|
||||||
* Try to load the module. */
|
|
||||||
err = request_module("rfkill-input");
|
|
||||||
if (err)
|
|
||||||
b43legacywarn(wl, "Failed to load the rfkill-input module."
|
|
||||||
"The built-in radio LED will not work.\n");
|
|
||||||
#endif /* CONFIG_RFKILL_INPUT */
|
|
||||||
|
|
||||||
err = input_register_polled_device(rfk->poll_dev);
|
|
||||||
if (err)
|
|
||||||
goto err_unreg_rfk;
|
|
||||||
|
|
||||||
rfk->registered = 1;
|
rfk->registered = 1;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
err_unreg_rfk:
|
err_free:
|
||||||
rfkill_unregister(rfk->rfkill);
|
rfkill_destroy(rfk->rfkill);
|
||||||
err_free_polldev:
|
out_error:
|
||||||
input_free_polled_device(rfk->poll_dev);
|
|
||||||
rfk->poll_dev = NULL;
|
|
||||||
err_freed_rfk:
|
|
||||||
rfk->rfkill = NULL;
|
|
||||||
out_error:
|
|
||||||
rfk->registered = 0;
|
rfk->registered = 0;
|
||||||
b43legacywarn(wl, "RF-kill button init failed\n");
|
b43legacywarn(wl, "RF-kill button init failed\n");
|
||||||
}
|
}
|
||||||
@ -199,10 +156,8 @@ void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
|
|||||||
return;
|
return;
|
||||||
rfk->registered = 0;
|
rfk->registered = 0;
|
||||||
|
|
||||||
input_unregister_polled_device(rfk->poll_dev);
|
|
||||||
rfkill_unregister(rfk->rfkill);
|
rfkill_unregister(rfk->rfkill);
|
||||||
input_free_polled_device(rfk->poll_dev);
|
rfkill_destroy(rfk->rfkill);
|
||||||
rfk->poll_dev = NULL;
|
|
||||||
rfk->rfkill = NULL;
|
rfk->rfkill = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,16 +6,12 @@ struct b43legacy_wldev;
|
|||||||
#ifdef CONFIG_B43LEGACY_RFKILL
|
#ifdef CONFIG_B43LEGACY_RFKILL
|
||||||
|
|
||||||
#include <linux/rfkill.h>
|
#include <linux/rfkill.h>
|
||||||
#include <linux/workqueue.h>
|
|
||||||
#include <linux/input-polldev.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct b43legacy_rfkill {
|
struct b43legacy_rfkill {
|
||||||
/* The RFKILL subsystem data structure */
|
/* The RFKILL subsystem data structure */
|
||||||
struct rfkill *rfkill;
|
struct rfkill *rfkill;
|
||||||
/* The poll device for the RFKILL input button */
|
|
||||||
struct input_polled_dev *poll_dev;
|
|
||||||
/* Did initialization succeed? Used for freeing. */
|
/* Did initialization succeed? Used for freeing. */
|
||||||
bool registered;
|
bool registered;
|
||||||
/* The unique name of this rfkill switch */
|
/* The unique name of this rfkill switch */
|
||||||
@ -27,7 +23,7 @@ struct b43legacy_rfkill {
|
|||||||
void b43legacy_rfkill_init(struct b43legacy_wldev *dev);
|
void b43legacy_rfkill_init(struct b43legacy_wldev *dev);
|
||||||
void b43legacy_rfkill_exit(struct b43legacy_wldev *dev);
|
void b43legacy_rfkill_exit(struct b43legacy_wldev *dev);
|
||||||
|
|
||||||
char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev);
|
const char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev);
|
||||||
|
|
||||||
|
|
||||||
#else /* CONFIG_B43LEGACY_RFKILL */
|
#else /* CONFIG_B43LEGACY_RFKILL */
|
||||||
|
@ -5,15 +5,14 @@ config IWLWIFI
|
|||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
select MAC80211_LEDS if IWLWIFI_LEDS
|
select MAC80211_LEDS if IWLWIFI_LEDS
|
||||||
select LEDS_CLASS if IWLWIFI_LEDS
|
select LEDS_CLASS if IWLWIFI_LEDS
|
||||||
select RFKILL if IWLWIFI_RFKILL
|
|
||||||
|
|
||||||
config IWLWIFI_LEDS
|
config IWLWIFI_LEDS
|
||||||
bool "Enable LED support in iwlagn and iwl3945 drivers"
|
bool "Enable LED support in iwlagn and iwl3945 drivers"
|
||||||
depends on IWLWIFI
|
depends on IWLWIFI
|
||||||
|
|
||||||
config IWLWIFI_RFKILL
|
config IWLWIFI_RFKILL
|
||||||
bool "Enable RF kill support in iwlagn and iwl3945 drivers"
|
def_bool y
|
||||||
depends on IWLWIFI
|
depends on IWLWIFI && RFKILL
|
||||||
|
|
||||||
config IWLWIFI_SPECTRUM_MEASUREMENT
|
config IWLWIFI_SPECTRUM_MEASUREMENT
|
||||||
bool "Enable Spectrum Measurement in iwlagn driver"
|
bool "Enable Spectrum Measurement in iwlagn driver"
|
||||||
|
@ -167,10 +167,6 @@ static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id)
|
|||||||
IWL_DEBUG_LED(priv, "Disassociated\n");
|
IWL_DEBUG_LED(priv, "Disassociated\n");
|
||||||
|
|
||||||
priv->allow_blinking = 0;
|
priv->allow_blinking = 0;
|
||||||
if (iwl_is_rfkill(priv))
|
|
||||||
iwl3945_led_off(priv, led_id);
|
|
||||||
else
|
|
||||||
iwl3945_led_on(priv, led_id);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include "iwl-commands.h"
|
#include "iwl-commands.h"
|
||||||
#include "iwl-3945.h"
|
#include "iwl-3945.h"
|
||||||
|
#include "iwl-sta.h"
|
||||||
|
|
||||||
#define RS_NAME "iwl-3945-rs"
|
#define RS_NAME "iwl-3945-rs"
|
||||||
|
|
||||||
@ -714,13 +715,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
|
|||||||
|
|
||||||
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
|
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
|
||||||
!rs_sta->ibss_sta_added) {
|
!rs_sta->ibss_sta_added) {
|
||||||
u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1);
|
u8 sta_id = iwl_find_station(priv, hdr->addr1);
|
||||||
|
|
||||||
if (sta_id == IWL_INVALID_STATION) {
|
if (sta_id == IWL_INVALID_STATION) {
|
||||||
IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n",
|
IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n",
|
||||||
hdr->addr1);
|
hdr->addr1);
|
||||||
sta_id = iwl3945_add_station(priv,
|
sta_id = iwl_add_station(priv, hdr->addr1, false,
|
||||||
hdr->addr1, 0, CMD_ASYNC, NULL);
|
CMD_ASYNC, NULL);
|
||||||
}
|
}
|
||||||
if (sta_id != IWL_INVALID_STATION)
|
if (sta_id != IWL_INVALID_STATION)
|
||||||
rs_sta->ibss_sta_added = 1;
|
rs_sta->ibss_sta_added = 1;
|
||||||
@ -975,7 +976,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
|
|||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
sta = ieee80211_find_sta(hw, priv->stations_39[sta_id].sta.sta.addr);
|
sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr);
|
||||||
if (!sta) {
|
if (!sta) {
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return;
|
return;
|
||||||
|
@ -769,35 +769,6 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
|
|||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 iwl3945_hw_find_station(struct iwl_priv *priv, const u8 *addr)
|
|
||||||
{
|
|
||||||
int i, start = IWL_AP_ID;
|
|
||||||
int ret = IWL_INVALID_STATION;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) ||
|
|
||||||
(priv->iw_mode == NL80211_IFTYPE_AP))
|
|
||||||
start = IWL_STA_ID;
|
|
||||||
|
|
||||||
if (is_broadcast_ether_addr(addr))
|
|
||||||
return priv->hw_params.bcast_sta_id;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
|
||||||
for (i = start; i < priv->hw_params.max_stations; i++)
|
|
||||||
if ((priv->stations_39[i].used) &&
|
|
||||||
(!compare_ether_addr
|
|
||||||
(priv->stations_39[i].sta.sta.addr, addr))) {
|
|
||||||
ret = i;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
IWL_DEBUG_INFO(priv, "can not find STA %pM (total %d)\n",
|
|
||||||
addr, priv->num_stations);
|
|
||||||
out:
|
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
|
* iwl3945_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
|
||||||
*
|
*
|
||||||
@ -875,13 +846,13 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv, struct iwl_cmd *cmd,
|
|||||||
u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
|
u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
|
||||||
{
|
{
|
||||||
unsigned long flags_spin;
|
unsigned long flags_spin;
|
||||||
struct iwl3945_station_entry *station;
|
struct iwl_station_entry *station;
|
||||||
|
|
||||||
if (sta_id == IWL_INVALID_STATION)
|
if (sta_id == IWL_INVALID_STATION)
|
||||||
return IWL_INVALID_STATION;
|
return IWL_INVALID_STATION;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||||
station = &priv->stations_39[sta_id];
|
station = &priv->stations[sta_id];
|
||||||
|
|
||||||
station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
|
station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
|
||||||
station->sta.rate_n_flags = cpu_to_le16(tx_rate);
|
station->sta.rate_n_flags = cpu_to_le16(tx_rate);
|
||||||
@ -889,8 +860,7 @@ u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
|
|||||||
|
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||||
|
|
||||||
iwl_send_add_sta(priv,
|
iwl_send_add_sta(priv, &station->sta, flags);
|
||||||
(struct iwl_addsta_cmd *)&station->sta, flags);
|
|
||||||
IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n",
|
IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n",
|
||||||
sta_id, tx_rate);
|
sta_id, tx_rate);
|
||||||
return sta_id;
|
return sta_id;
|
||||||
@ -2029,7 +1999,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
|
|||||||
|
|
||||||
memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
|
memcpy(active_rxon, staging_rxon, sizeof(*active_rxon));
|
||||||
|
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
/* If we issue a new RXON command which required a tune then we must
|
/* If we issue a new RXON command which required a tune then we must
|
||||||
* send a new TXPOWER command or we won't be able to Tx any frames */
|
* send a new TXPOWER command or we won't be able to Tx any frames */
|
||||||
@ -2040,7 +2010,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add the broadcast address so we can send broadcast frames */
|
/* Add the broadcast address so we can send broadcast frames */
|
||||||
if (priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL) ==
|
if (iwl_add_station(priv, iwl_bcast_addr, false, CMD_SYNC, NULL) ==
|
||||||
IWL_INVALID_STATION) {
|
IWL_INVALID_STATION) {
|
||||||
IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n");
|
IWL_ERR(priv, "Error adding BROADCAST address for transmit.\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
@ -2050,9 +2020,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
|
|||||||
* add the IWL_AP_ID to the station rate table */
|
* add the IWL_AP_ID to the station rate table */
|
||||||
if (iwl_is_associated(priv) &&
|
if (iwl_is_associated(priv) &&
|
||||||
(priv->iw_mode == NL80211_IFTYPE_STATION))
|
(priv->iw_mode == NL80211_IFTYPE_STATION))
|
||||||
if (priv->cfg->ops->smgmt->add_station(priv,
|
if (iwl_add_station(priv, priv->active_rxon.bssid_addr,
|
||||||
priv->active_rxon.bssid_addr, 1, 0, NULL)
|
true, CMD_SYNC, NULL) == IWL_INVALID_STATION) {
|
||||||
== IWL_INVALID_STATION) {
|
|
||||||
IWL_ERR(priv, "Error adding AP address for transmit\n");
|
IWL_ERR(priv, "Error adding AP address for transmit\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
@ -2466,13 +2435,25 @@ static u16 iwl3945_get_hcmd_size(u8 cmd_id, u16 len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
|
static u16 iwl3945_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
|
||||||
{
|
{
|
||||||
u16 size = (u16)sizeof(struct iwl3945_addsta_cmd);
|
struct iwl3945_addsta_cmd *addsta = (struct iwl3945_addsta_cmd *)data;
|
||||||
memcpy(data, cmd, size);
|
addsta->mode = cmd->mode;
|
||||||
return size;
|
memcpy(&addsta->sta, &cmd->sta, sizeof(struct sta_id_modify));
|
||||||
|
memcpy(&addsta->key, &cmd->key, sizeof(struct iwl4965_keyinfo));
|
||||||
|
addsta->station_flags = cmd->station_flags;
|
||||||
|
addsta->station_flags_msk = cmd->station_flags_msk;
|
||||||
|
addsta->tid_disable_tx = cpu_to_le16(0);
|
||||||
|
addsta->rate_n_flags = cmd->rate_n_flags;
|
||||||
|
addsta->add_immediate_ba_tid = cmd->add_immediate_ba_tid;
|
||||||
|
addsta->remove_immediate_ba_tid = cmd->remove_immediate_ba_tid;
|
||||||
|
addsta->add_immediate_ba_ssn = cmd->add_immediate_ba_ssn;
|
||||||
|
|
||||||
|
return (u16)sizeof(struct iwl3945_addsta_cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table
|
* iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table
|
||||||
*/
|
*/
|
||||||
@ -2842,15 +2823,6 @@ static struct iwl_lib_ops iwl3945_lib = {
|
|||||||
.config_ap = iwl3945_config_ap,
|
.config_ap = iwl3945_config_ap,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct iwl_station_mgmt_ops iwl3945_station_mgmt = {
|
|
||||||
.add_station = iwl3945_add_station,
|
|
||||||
#if 0
|
|
||||||
.remove_station = iwl3945_remove_station,
|
|
||||||
#endif
|
|
||||||
.find_station = iwl3945_hw_find_station,
|
|
||||||
.clear_station_table = iwl3945_clear_stations_table,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
|
static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
|
||||||
.get_hcmd_size = iwl3945_get_hcmd_size,
|
.get_hcmd_size = iwl3945_get_hcmd_size,
|
||||||
.build_addsta_hcmd = iwl3945_build_addsta_hcmd,
|
.build_addsta_hcmd = iwl3945_build_addsta_hcmd,
|
||||||
@ -2860,7 +2832,6 @@ static struct iwl_ops iwl3945_ops = {
|
|||||||
.lib = &iwl3945_lib,
|
.lib = &iwl3945_lib,
|
||||||
.hcmd = &iwl3945_hcmd,
|
.hcmd = &iwl3945_hcmd,
|
||||||
.utils = &iwl3945_hcmd_utils,
|
.utils = &iwl3945_hcmd_utils,
|
||||||
.smgmt = &iwl3945_station_mgmt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct iwl_cfg iwl3945_bg_cfg = {
|
static struct iwl_cfg iwl3945_bg_cfg = {
|
||||||
|
@ -202,12 +202,6 @@ struct iwl3945_ibss_seq {
|
|||||||
* for use by iwl-*.c
|
* for use by iwl-*.c
|
||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
struct iwl3945_addsta_cmd;
|
|
||||||
extern int iwl3945_send_add_station(struct iwl_priv *priv,
|
|
||||||
struct iwl3945_addsta_cmd *sta, u8 flags);
|
|
||||||
extern u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *bssid,
|
|
||||||
int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
|
|
||||||
extern void iwl3945_clear_stations_table(struct iwl_priv *priv);
|
|
||||||
extern int iwl3945_power_init_handle(struct iwl_priv *priv);
|
extern int iwl3945_power_init_handle(struct iwl_priv *priv);
|
||||||
extern int iwl3945_eeprom_init(struct iwl_priv *priv);
|
extern int iwl3945_eeprom_init(struct iwl_priv *priv);
|
||||||
extern int iwl3945_calc_db_from_ratio(int sig_ratio);
|
extern int iwl3945_calc_db_from_ratio(int sig_ratio);
|
||||||
|
@ -2221,13 +2221,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
|
|||||||
cancel_work_sync(&priv->txpower_work);
|
cancel_work_sync(&priv->txpower_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct iwl_station_mgmt_ops iwl4965_station_mgmt = {
|
|
||||||
.add_station = iwl_add_station_flags,
|
|
||||||
.remove_station = iwl_remove_station,
|
|
||||||
.find_station = iwl_find_station,
|
|
||||||
.clear_station_table = iwl_clear_stations_table,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct iwl_hcmd_ops iwl4965_hcmd = {
|
static struct iwl_hcmd_ops iwl4965_hcmd = {
|
||||||
.rxon_assoc = iwl4965_send_rxon_assoc,
|
.rxon_assoc = iwl4965_send_rxon_assoc,
|
||||||
.commit_rxon = iwl_commit_rxon,
|
.commit_rxon = iwl_commit_rxon,
|
||||||
@ -2297,7 +2290,6 @@ static struct iwl_ops iwl4965_ops = {
|
|||||||
.lib = &iwl4965_lib,
|
.lib = &iwl4965_lib,
|
||||||
.hcmd = &iwl4965_hcmd,
|
.hcmd = &iwl4965_hcmd,
|
||||||
.utils = &iwl4965_hcmd_utils,
|
.utils = &iwl4965_hcmd_utils,
|
||||||
.smgmt = &iwl4965_station_mgmt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_cfg iwl4965_agn_cfg = {
|
struct iwl_cfg iwl4965_agn_cfg = {
|
||||||
|
@ -651,7 +651,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv)
|
|||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
ret = priv->cfg->ops->lib->alive_notify(priv);
|
ret = priv->cfg->ops->lib->alive_notify(priv);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
IWL_WARN(priv,
|
IWL_WARN(priv,
|
||||||
@ -1049,7 +1049,10 @@ static int iwl5000_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
|
|||||||
u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
|
u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
|
||||||
{
|
{
|
||||||
u16 size = (u16)sizeof(struct iwl_addsta_cmd);
|
u16 size = (u16)sizeof(struct iwl_addsta_cmd);
|
||||||
memcpy(data, cmd, size);
|
struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data;
|
||||||
|
memcpy(addsta, cmd, size);
|
||||||
|
/* resrved in 5000 */
|
||||||
|
addsta->rate_n_flags = cpu_to_le16(0);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1423,13 +1426,6 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
|
|||||||
return max_rssi - agc - IWL49_RSSI_OFFSET;
|
return max_rssi - agc - IWL49_RSSI_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct iwl_station_mgmt_ops iwl5000_station_mgmt = {
|
|
||||||
.add_station = iwl_add_station_flags,
|
|
||||||
.remove_station = iwl_remove_station,
|
|
||||||
.find_station = iwl_find_station,
|
|
||||||
.clear_station_table = iwl_clear_stations_table,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct iwl_hcmd_ops iwl5000_hcmd = {
|
struct iwl_hcmd_ops iwl5000_hcmd = {
|
||||||
.rxon_assoc = iwl5000_send_rxon_assoc,
|
.rxon_assoc = iwl5000_send_rxon_assoc,
|
||||||
.commit_rxon = iwl_commit_rxon,
|
.commit_rxon = iwl_commit_rxon,
|
||||||
@ -1549,14 +1545,12 @@ struct iwl_ops iwl5000_ops = {
|
|||||||
.lib = &iwl5000_lib,
|
.lib = &iwl5000_lib,
|
||||||
.hcmd = &iwl5000_hcmd,
|
.hcmd = &iwl5000_hcmd,
|
||||||
.utils = &iwl5000_hcmd_utils,
|
.utils = &iwl5000_hcmd_utils,
|
||||||
.smgmt = &iwl5000_station_mgmt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct iwl_ops iwl5150_ops = {
|
static struct iwl_ops iwl5150_ops = {
|
||||||
.lib = &iwl5150_lib,
|
.lib = &iwl5150_lib,
|
||||||
.hcmd = &iwl5000_hcmd,
|
.hcmd = &iwl5000_hcmd,
|
||||||
.utils = &iwl5000_hcmd_utils,
|
.utils = &iwl5000_hcmd_utils,
|
||||||
.smgmt = &iwl5000_station_mgmt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_mod_params iwl50_mod_params = {
|
struct iwl_mod_params iwl50_mod_params = {
|
||||||
|
@ -72,7 +72,6 @@ static struct iwl_ops iwl6000_ops = {
|
|||||||
.lib = &iwl5000_lib,
|
.lib = &iwl5000_lib,
|
||||||
.hcmd = &iwl5000_hcmd,
|
.hcmd = &iwl5000_hcmd,
|
||||||
.utils = &iwl6000_hcmd_utils,
|
.utils = &iwl6000_hcmd_utils,
|
||||||
.smgmt = &iwl5000_station_mgmt,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_cfg iwl6000_2ag_cfg = {
|
struct iwl_cfg iwl6000_2ag_cfg = {
|
||||||
|
@ -2502,15 +2502,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
|
|||||||
|
|
||||||
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
|
if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) &&
|
||||||
!lq_sta->ibss_sta_added) {
|
!lq_sta->ibss_sta_added) {
|
||||||
u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
|
u8 sta_id = iwl_find_station(priv, hdr->addr1);
|
||||||
hdr->addr1);
|
|
||||||
|
|
||||||
if (sta_id == IWL_INVALID_STATION) {
|
if (sta_id == IWL_INVALID_STATION) {
|
||||||
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
|
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
|
||||||
hdr->addr1);
|
hdr->addr1);
|
||||||
sta_id = priv->cfg->ops->smgmt->add_station(priv,
|
sta_id = iwl_add_station(priv, hdr->addr1,
|
||||||
hdr->addr1, 0,
|
false, CMD_ASYNC, NULL);
|
||||||
CMD_ASYNC, NULL);
|
|
||||||
}
|
}
|
||||||
if ((sta_id != IWL_INVALID_STATION)) {
|
if ((sta_id != IWL_INVALID_STATION)) {
|
||||||
lq_sta->lq.sta_id = sta_id;
|
lq_sta->lq.sta_id = sta_id;
|
||||||
@ -2598,7 +2596,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
|
|||||||
|
|
||||||
lq_sta->ibss_sta_added = 0;
|
lq_sta->ibss_sta_added = 0;
|
||||||
if (priv->iw_mode == NL80211_IFTYPE_AP) {
|
if (priv->iw_mode == NL80211_IFTYPE_AP) {
|
||||||
u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
|
u8 sta_id = iwl_find_station(priv,
|
||||||
sta->addr);
|
sta->addr);
|
||||||
|
|
||||||
/* for IBSS the call are from tasklet */
|
/* for IBSS the call are from tasklet */
|
||||||
@ -2606,9 +2604,8 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband,
|
|||||||
|
|
||||||
if (sta_id == IWL_INVALID_STATION) {
|
if (sta_id == IWL_INVALID_STATION) {
|
||||||
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
|
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
|
||||||
sta_id = priv->cfg->ops->smgmt->add_station(priv,
|
sta_id = iwl_add_station(priv, sta->addr, false,
|
||||||
sta->addr, 0,
|
CMD_ASYNC, NULL);
|
||||||
CMD_ASYNC, NULL);
|
|
||||||
}
|
}
|
||||||
if ((sta_id != IWL_INVALID_STATION)) {
|
if ((sta_id != IWL_INVALID_STATION)) {
|
||||||
lq_sta->lq.sta_id = sta_id;
|
lq_sta->lq.sta_id = sta_id;
|
||||||
@ -2790,9 +2787,10 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv,
|
|||||||
repeat_rate--;
|
repeat_rate--;
|
||||||
}
|
}
|
||||||
|
|
||||||
lq_cmd->agg_params.agg_frame_cnt_limit = 64;
|
lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX;
|
||||||
lq_cmd->agg_params.agg_dis_start_th = 3;
|
lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
|
||||||
lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
|
lq_cmd->agg_params.agg_time_limit =
|
||||||
|
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
|
||||||
|
@ -188,7 +188,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
|
|||||||
memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
|
memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
priv->start_calib = 0;
|
priv->start_calib = 0;
|
||||||
|
|
||||||
@ -1617,7 +1617,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
|
|||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
ret = priv->cfg->ops->lib->alive_notify(priv);
|
ret = priv->cfg->ops->lib->alive_notify(priv);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
IWL_WARN(priv,
|
IWL_WARN(priv,
|
||||||
@ -1703,7 +1703,7 @@ static void __iwl_down(struct iwl_priv *priv)
|
|||||||
|
|
||||||
iwl_leds_unregister(priv);
|
iwl_leds_unregister(priv);
|
||||||
|
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
/* Unblock any waiting calls */
|
/* Unblock any waiting calls */
|
||||||
wake_up_interruptible_all(&priv->wait_command_queue);
|
wake_up_interruptible_all(&priv->wait_command_queue);
|
||||||
@ -1887,8 +1887,6 @@ static int __iwl_up(struct iwl_priv *priv)
|
|||||||
|
|
||||||
/* clear (again), then enable host interrupts */
|
/* clear (again), then enable host interrupts */
|
||||||
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
|
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
|
||||||
/* enable dram interrupt */
|
|
||||||
iwl_reset_ict(priv);
|
|
||||||
iwl_enable_interrupts(priv);
|
iwl_enable_interrupts(priv);
|
||||||
|
|
||||||
/* really make sure rfkill handshake bits are cleared */
|
/* really make sure rfkill handshake bits are cleared */
|
||||||
@ -1903,7 +1901,7 @@ static int __iwl_up(struct iwl_priv *priv)
|
|||||||
|
|
||||||
for (i = 0; i < MAX_HW_RESTARTS; i++) {
|
for (i = 0; i < MAX_HW_RESTARTS; i++) {
|
||||||
|
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
/* load bootstrap state machine,
|
/* load bootstrap state machine,
|
||||||
* load bootstrap program into processor's memory,
|
* load bootstrap program into processor's memory,
|
||||||
@ -1962,6 +1960,9 @@ static void iwl_bg_alive_start(struct work_struct *data)
|
|||||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* enable dram interrupt */
|
||||||
|
iwl_reset_ict(priv);
|
||||||
|
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
iwl_alive_start(priv);
|
iwl_alive_start(priv);
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
@ -2348,7 +2349,7 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
addr = sta ? sta->addr : iwl_bcast_addr;
|
addr = sta ? sta->addr : iwl_bcast_addr;
|
||||||
sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
|
sta_id = iwl_find_station(priv, addr);
|
||||||
if (sta_id == IWL_INVALID_STATION) {
|
if (sta_id == IWL_INVALID_STATION) {
|
||||||
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
|
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
|
||||||
addr);
|
addr);
|
||||||
@ -3121,7 +3122,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
|
|||||||
iwl_rx_queue_free(priv, &priv->rxq);
|
iwl_rx_queue_free(priv, &priv->rxq);
|
||||||
iwl_hw_txq_ctx_free(priv);
|
iwl_hw_txq_ctx_free(priv);
|
||||||
|
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
iwl_eeprom_free(priv);
|
iwl_eeprom_free(priv);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1067,7 +1067,7 @@ struct iwl_addsta_cmd {
|
|||||||
* Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
|
* Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
|
||||||
__le16 tid_disable_tx;
|
__le16 tid_disable_tx;
|
||||||
|
|
||||||
__le16 reserved1;
|
__le16 rate_n_flags; /* 3945 only */
|
||||||
|
|
||||||
/* TID for which to add block-ack support.
|
/* TID for which to add block-ack support.
|
||||||
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
|
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
|
||||||
@ -1913,6 +1913,18 @@ struct iwl_link_qual_general_params {
|
|||||||
u8 start_rate_index[LINK_QUAL_AC_NUM];
|
u8 start_rate_index[LINK_QUAL_AC_NUM];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
|
||||||
|
#define LINK_QUAL_AGG_TIME_LIMIT_MAX (65535)
|
||||||
|
#define LINK_QUAL_AGG_TIME_LIMIT_MIN (0)
|
||||||
|
|
||||||
|
#define LINK_QUAL_AGG_DISABLE_START_DEF (3)
|
||||||
|
#define LINK_QUAL_AGG_DISABLE_START_MAX (255)
|
||||||
|
#define LINK_QUAL_AGG_DISABLE_START_MIN (0)
|
||||||
|
|
||||||
|
#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31)
|
||||||
|
#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (64)
|
||||||
|
#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct iwl_link_qual_agg_params
|
* struct iwl_link_qual_agg_params
|
||||||
*
|
*
|
||||||
|
@ -1389,7 +1389,7 @@ int iwl_init_drv(struct iwl_priv *priv)
|
|||||||
mutex_init(&priv->mutex);
|
mutex_init(&priv->mutex);
|
||||||
|
|
||||||
/* Clear the driver's (not device's) station table */
|
/* Clear the driver's (not device's) station table */
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
priv->data_retry_limit = -1;
|
priv->data_retry_limit = -1;
|
||||||
priv->ieee_channels = NULL;
|
priv->ieee_channels = NULL;
|
||||||
@ -1704,8 +1704,9 @@ static irqreturn_t iwl_isr(int irq, void *data)
|
|||||||
{
|
{
|
||||||
struct iwl_priv *priv = data;
|
struct iwl_priv *priv = data;
|
||||||
u32 inta, inta_mask;
|
u32 inta, inta_mask;
|
||||||
|
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||||
u32 inta_fh;
|
u32 inta_fh;
|
||||||
|
#endif
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
@ -2679,19 +2680,12 @@ int iwl_set_mode(struct iwl_priv *priv, int mode)
|
|||||||
|
|
||||||
memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
|
memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
|
||||||
|
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
/* dont commit rxon if rf-kill is on*/
|
/* dont commit rxon if rf-kill is on*/
|
||||||
if (!iwl_is_ready_rf(priv))
|
if (!iwl_is_ready_rf(priv))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
cancel_delayed_work(&priv->scan_check);
|
|
||||||
if (iwl_scan_cancel_timeout(priv, 100)) {
|
|
||||||
IWL_WARN(priv, "Aborted scan still in progress after 100ms\n");
|
|
||||||
IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n");
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
iwlcore_commit_rxon(priv);
|
iwlcore_commit_rxon(priv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -83,15 +83,6 @@ struct iwl_cmd;
|
|||||||
#define IWL_SKU_A 0x2
|
#define IWL_SKU_A 0x2
|
||||||
#define IWL_SKU_N 0x8
|
#define IWL_SKU_N 0x8
|
||||||
|
|
||||||
struct iwl_station_mgmt_ops {
|
|
||||||
u8 (*add_station)(struct iwl_priv *priv, const u8 *addr,
|
|
||||||
int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info);
|
|
||||||
int (*remove_station)(struct iwl_priv *priv, const u8 *addr,
|
|
||||||
int is_ap);
|
|
||||||
u8 (*find_station)(struct iwl_priv *priv, const u8 *addr);
|
|
||||||
void (*clear_station_table)(struct iwl_priv *priv);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct iwl_hcmd_ops {
|
struct iwl_hcmd_ops {
|
||||||
int (*rxon_assoc)(struct iwl_priv *priv);
|
int (*rxon_assoc)(struct iwl_priv *priv);
|
||||||
int (*commit_rxon)(struct iwl_priv *priv);
|
int (*commit_rxon)(struct iwl_priv *priv);
|
||||||
@ -183,7 +174,6 @@ struct iwl_ops {
|
|||||||
const struct iwl_lib_ops *lib;
|
const struct iwl_lib_ops *lib;
|
||||||
const struct iwl_hcmd_ops *hcmd;
|
const struct iwl_hcmd_ops *hcmd;
|
||||||
const struct iwl_hcmd_utils_ops *utils;
|
const struct iwl_hcmd_utils_ops *utils;
|
||||||
const struct iwl_station_mgmt_ops *smgmt;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct iwl_mod_params {
|
struct iwl_mod_params {
|
||||||
@ -192,7 +182,7 @@ struct iwl_mod_params {
|
|||||||
int disable_hw_scan; /* def: 0 = use h/w scan */
|
int disable_hw_scan; /* def: 0 = use h/w scan */
|
||||||
int num_of_queues; /* def: HW dependent */
|
int num_of_queues; /* def: HW dependent */
|
||||||
int num_of_ampdu_queues;/* def: HW dependent */
|
int num_of_ampdu_queues;/* def: HW dependent */
|
||||||
int disable_11n; /* def: 0 = disable 11n capabilities */
|
int disable_11n; /* def: 0 = 11n capabilities enabled */
|
||||||
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
|
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
|
||||||
int antenna; /* def: 0 = both antennas (use diversity) */
|
int antenna; /* def: 0 = both antennas (use diversity) */
|
||||||
int restart_fw; /* def: 1 = restart firmware */
|
int restart_fw; /* def: 1 = restart firmware */
|
||||||
|
@ -70,7 +70,6 @@ extern struct iwl_ops iwl5000_ops;
|
|||||||
extern struct iwl_lib_ops iwl5000_lib;
|
extern struct iwl_lib_ops iwl5000_lib;
|
||||||
extern struct iwl_hcmd_ops iwl5000_hcmd;
|
extern struct iwl_hcmd_ops iwl5000_hcmd;
|
||||||
extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
|
extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
|
||||||
extern struct iwl_station_mgmt_ops iwl5000_station_mgmt;
|
|
||||||
|
|
||||||
/* shared functions from iwl-5000.c */
|
/* shared functions from iwl-5000.c */
|
||||||
extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len);
|
extern u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len);
|
||||||
@ -290,11 +289,11 @@ struct iwl_frame {
|
|||||||
#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
|
#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* CMD_SIZE_NORMAL = 0, */
|
CMD_SYNC = 0,
|
||||||
|
CMD_SIZE_NORMAL = 0,
|
||||||
|
CMD_NO_SKB = 0,
|
||||||
CMD_SIZE_HUGE = (1 << 0),
|
CMD_SIZE_HUGE = (1 << 0),
|
||||||
/* CMD_SYNC = 0, */
|
|
||||||
CMD_ASYNC = (1 << 1),
|
CMD_ASYNC = (1 << 1),
|
||||||
/* CMD_NO_SKB = 0, */
|
|
||||||
CMD_WANT_SKB = (1 << 2),
|
CMD_WANT_SKB = (1 << 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1119,8 +1118,6 @@ struct iwl_priv {
|
|||||||
|
|
||||||
struct iwl3945_notif_statistics statistics_39;
|
struct iwl3945_notif_statistics statistics_39;
|
||||||
|
|
||||||
struct iwl3945_station_entry stations_39[IWL_STATION_COUNT];
|
|
||||||
|
|
||||||
u32 sta_supp_rates;
|
u32 sta_supp_rates;
|
||||||
}; /*iwl_priv */
|
}; /*iwl_priv */
|
||||||
|
|
||||||
|
@ -240,13 +240,11 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
IWL_ERR(priv, "Time out access OTP\n");
|
IWL_ERR(priv, "Time out access OTP\n");
|
||||||
else {
|
else {
|
||||||
if (!ret) {
|
iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
|
||||||
iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
|
APMG_PS_CTRL_VAL_RESET_REQ);
|
||||||
APMG_PS_CTRL_VAL_RESET_REQ);
|
udelay(5);
|
||||||
udelay(5);
|
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
|
||||||
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
|
APMG_PS_CTRL_VAL_RESET_REQ);
|
||||||
APMG_PS_CTRL_VAL_RESET_REQ);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -176,10 +176,6 @@ static int iwl_led_associate(struct iwl_priv *priv, int led_id)
|
|||||||
static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
|
static int iwl_led_disassociate(struct iwl_priv *priv, int led_id)
|
||||||
{
|
{
|
||||||
priv->allow_blinking = 0;
|
priv->allow_blinking = 0;
|
||||||
if (iwl_is_rfkill(priv))
|
|
||||||
iwl4965_led_off_reg(priv, led_id);
|
|
||||||
else
|
|
||||||
iwl4965_led_on_reg(priv, led_id);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -36,42 +36,37 @@
|
|||||||
#include "iwl-core.h"
|
#include "iwl-core.h"
|
||||||
|
|
||||||
/* software rf-kill from user */
|
/* software rf-kill from user */
|
||||||
static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state)
|
static int iwl_rfkill_soft_rf_kill(void *data, bool blocked)
|
||||||
{
|
{
|
||||||
struct iwl_priv *priv = data;
|
struct iwl_priv *priv = data;
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!priv->rfkill)
|
if (!priv->rfkill)
|
||||||
return 0;
|
return -EINVAL;
|
||||||
|
|
||||||
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
IWL_DEBUG_RF_KILL(priv, "we received soft RFKILL set to state %d\n", state);
|
IWL_DEBUG_RF_KILL(priv, "received soft RFKILL: block=%d\n", blocked);
|
||||||
|
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
|
|
||||||
switch (state) {
|
if (iwl_is_rfkill_hw(priv))
|
||||||
case RFKILL_STATE_UNBLOCKED:
|
goto out_unlock;
|
||||||
if (iwl_is_rfkill_hw(priv)) {
|
|
||||||
err = -EBUSY;
|
if (!blocked)
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
iwl_radio_kill_sw_enable_radio(priv);
|
iwl_radio_kill_sw_enable_radio(priv);
|
||||||
break;
|
else
|
||||||
case RFKILL_STATE_SOFT_BLOCKED:
|
|
||||||
iwl_radio_kill_sw_disable_radio(priv);
|
iwl_radio_kill_sw_disable_radio(priv);
|
||||||
break;
|
|
||||||
default:
|
|
||||||
IWL_WARN(priv, "we received unexpected RFKILL state %d\n",
|
|
||||||
state);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&priv->mutex);
|
mutex_unlock(&priv->mutex);
|
||||||
|
return 0;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct rfkill_ops iwl_rfkill_ops = {
|
||||||
|
.set_block = iwl_rfkill_soft_rf_kill,
|
||||||
|
};
|
||||||
|
|
||||||
int iwl_rfkill_init(struct iwl_priv *priv)
|
int iwl_rfkill_init(struct iwl_priv *priv)
|
||||||
{
|
{
|
||||||
struct device *device = wiphy_dev(priv->hw->wiphy);
|
struct device *device = wiphy_dev(priv->hw->wiphy);
|
||||||
@ -80,21 +75,16 @@ int iwl_rfkill_init(struct iwl_priv *priv)
|
|||||||
BUG_ON(device == NULL);
|
BUG_ON(device == NULL);
|
||||||
|
|
||||||
IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n");
|
IWL_DEBUG_RF_KILL(priv, "Initializing RFKILL.\n");
|
||||||
priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
|
priv->rfkill = rfkill_alloc(priv->cfg->name,
|
||||||
|
device,
|
||||||
|
RFKILL_TYPE_WLAN,
|
||||||
|
&iwl_rfkill_ops, priv);
|
||||||
if (!priv->rfkill) {
|
if (!priv->rfkill) {
|
||||||
IWL_ERR(priv, "Unable to allocate RFKILL device.\n");
|
IWL_ERR(priv, "Unable to allocate RFKILL device.\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->rfkill->name = priv->cfg->name;
|
|
||||||
priv->rfkill->data = priv;
|
|
||||||
priv->rfkill->state = RFKILL_STATE_UNBLOCKED;
|
|
||||||
priv->rfkill->toggle_radio = iwl_rfkill_soft_rf_kill;
|
|
||||||
|
|
||||||
priv->rfkill->dev.class->suspend = NULL;
|
|
||||||
priv->rfkill->dev.class->resume = NULL;
|
|
||||||
|
|
||||||
ret = rfkill_register(priv->rfkill);
|
ret = rfkill_register(priv->rfkill);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret);
|
IWL_ERR(priv, "Unable to register RFKILL: %d\n", ret);
|
||||||
@ -102,11 +92,10 @@ int iwl_rfkill_init(struct iwl_priv *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n");
|
IWL_DEBUG_RF_KILL(priv, "RFKILL initialization complete.\n");
|
||||||
return ret;
|
return 0;
|
||||||
|
|
||||||
free_rfkill:
|
free_rfkill:
|
||||||
if (priv->rfkill != NULL)
|
rfkill_destroy(priv->rfkill);
|
||||||
rfkill_free(priv->rfkill);
|
|
||||||
priv->rfkill = NULL;
|
priv->rfkill = NULL;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
@ -118,8 +107,10 @@ EXPORT_SYMBOL(iwl_rfkill_init);
|
|||||||
void iwl_rfkill_unregister(struct iwl_priv *priv)
|
void iwl_rfkill_unregister(struct iwl_priv *priv)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (priv->rfkill)
|
if (priv->rfkill) {
|
||||||
rfkill_unregister(priv->rfkill);
|
rfkill_unregister(priv->rfkill);
|
||||||
|
rfkill_destroy(priv->rfkill);
|
||||||
|
}
|
||||||
|
|
||||||
priv->rfkill = NULL;
|
priv->rfkill = NULL;
|
||||||
}
|
}
|
||||||
@ -131,14 +122,10 @@ void iwl_rfkill_set_hw_state(struct iwl_priv *priv)
|
|||||||
if (!priv->rfkill)
|
if (!priv->rfkill)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (iwl_is_rfkill_hw(priv)) {
|
if (rfkill_set_hw_state(priv->rfkill,
|
||||||
rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED);
|
!!iwl_is_rfkill_hw(priv)))
|
||||||
return;
|
iwl_radio_kill_sw_disable_radio(priv);
|
||||||
}
|
|
||||||
|
|
||||||
if (!iwl_is_rfkill_sw(priv))
|
|
||||||
rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED);
|
|
||||||
else
|
else
|
||||||
rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED);
|
iwl_radio_kill_sw_enable_radio(priv);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_rfkill_set_hw_state);
|
EXPORT_SYMBOL(iwl_rfkill_set_hw_state);
|
||||||
|
@ -75,7 +75,7 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
|
|||||||
return IWL_AP_ID;
|
return IWL_AP_ID;
|
||||||
} else {
|
} else {
|
||||||
u8 *da = ieee80211_get_DA(hdr);
|
u8 *da = ieee80211_get_DA(hdr);
|
||||||
return priv->cfg->ops->smgmt->find_station(priv, da);
|
return iwl_find_station(priv, da);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_get_ra_sta_id);
|
EXPORT_SYMBOL(iwl_get_ra_sta_id);
|
||||||
@ -86,8 +86,7 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
|
|||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||||
|
|
||||||
if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
|
if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
|
||||||
!(priv->stations_39[sta_id].used & IWL_STA_DRIVER_ACTIVE))
|
|
||||||
IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n",
|
IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n",
|
||||||
sta_id);
|
sta_id);
|
||||||
|
|
||||||
@ -228,15 +227,16 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iwl_add_station_flags - Add station to tables in driver and device
|
* iwl_add_station - Add station to tables in driver and device
|
||||||
*/
|
*/
|
||||||
u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
|
u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
|
||||||
u8 flags, struct ieee80211_sta_ht_cap *ht_info)
|
struct ieee80211_sta_ht_cap *ht_info)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
int sta_id = IWL_INVALID_STATION;
|
|
||||||
struct iwl_station_entry *station;
|
struct iwl_station_entry *station;
|
||||||
unsigned long flags_spin;
|
unsigned long flags_spin;
|
||||||
|
int i;
|
||||||
|
int sta_id = IWL_INVALID_STATION;
|
||||||
|
u16 rate;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
||||||
if (is_ap)
|
if (is_ap)
|
||||||
@ -288,6 +288,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
|
|||||||
priv->iw_mode != NL80211_IFTYPE_ADHOC)
|
priv->iw_mode != NL80211_IFTYPE_ADHOC)
|
||||||
iwl_set_ht_add_station(priv, sta_id, ht_info);
|
iwl_set_ht_add_station(priv, sta_id, ht_info);
|
||||||
|
|
||||||
|
/* 3945 only */
|
||||||
|
rate = (priv->band == IEEE80211_BAND_5GHZ) ?
|
||||||
|
IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP;
|
||||||
|
/* Turn on both antennas for the station... */
|
||||||
|
station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
||||||
|
|
||||||
/* Add station to device's station table */
|
/* Add station to device's station table */
|
||||||
@ -295,12 +301,12 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap,
|
|||||||
return sta_id;
|
return sta_id;
|
||||||
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(iwl_add_station_flags);
|
EXPORT_SYMBOL(iwl_add_station);
|
||||||
|
|
||||||
static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
|
static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
|
u8 sta_id = iwl_find_station(priv, addr);
|
||||||
|
|
||||||
BUG_ON(sta_id == IWL_INVALID_STATION);
|
BUG_ON(sta_id == IWL_INVALID_STATION);
|
||||||
|
|
||||||
@ -408,7 +414,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv, const u8 *addr,
|
|||||||
/**
|
/**
|
||||||
* iwl_remove_station - Remove driver's knowledge of station.
|
* iwl_remove_station - Remove driver's knowledge of station.
|
||||||
*/
|
*/
|
||||||
int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
|
int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
|
||||||
{
|
{
|
||||||
int sta_id = IWL_INVALID_STATION;
|
int sta_id = IWL_INVALID_STATION;
|
||||||
int i, ret = -EINVAL;
|
int i, ret = -EINVAL;
|
||||||
@ -767,7 +773,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
|
sta_id = iwl_find_station(priv, addr);
|
||||||
if (sta_id == IWL_INVALID_STATION) {
|
if (sta_id == IWL_INVALID_STATION) {
|
||||||
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
|
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
|
||||||
addr);
|
addr);
|
||||||
@ -946,7 +952,7 @@ EXPORT_SYMBOL(iwl_send_lq_cmd);
|
|||||||
* calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
|
* calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
|
||||||
* which requires station table entry to exist).
|
* which requires station table entry to exist).
|
||||||
*/
|
*/
|
||||||
static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
|
static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, bool is_ap)
|
||||||
{
|
{
|
||||||
int i, r;
|
int i, r;
|
||||||
struct iwl_link_quality_cmd link_cmd = {
|
struct iwl_link_quality_cmd link_cmd = {
|
||||||
@ -979,8 +985,9 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
|
|||||||
link_cmd.general_params.single_stream_ant_msk =
|
link_cmd.general_params.single_stream_ant_msk =
|
||||||
first_antenna(priv->hw_params.valid_tx_ant);
|
first_antenna(priv->hw_params.valid_tx_ant);
|
||||||
link_cmd.general_params.dual_stream_ant_msk = 3;
|
link_cmd.general_params.dual_stream_ant_msk = 3;
|
||||||
link_cmd.agg_params.agg_dis_start_th = 3;
|
link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
|
||||||
link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
|
link_cmd.agg_params.agg_time_limit =
|
||||||
|
cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
|
||||||
|
|
||||||
/* Update the rate scaling for control frame Tx to AP */
|
/* Update the rate scaling for control frame Tx to AP */
|
||||||
link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
|
link_cmd.sta_id = is_ap ? IWL_AP_ID : priv->hw_params.bcast_sta_id;
|
||||||
@ -995,7 +1002,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap)
|
|||||||
* there is only one AP station with id= IWL_AP_ID
|
* there is only one AP station with id= IWL_AP_ID
|
||||||
* NOTE: mutex must be held before calling this function
|
* NOTE: mutex must be held before calling this function
|
||||||
*/
|
*/
|
||||||
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
|
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap)
|
||||||
{
|
{
|
||||||
struct ieee80211_sta *sta;
|
struct ieee80211_sta *sta;
|
||||||
struct ieee80211_sta_ht_cap ht_config;
|
struct ieee80211_sta_ht_cap ht_config;
|
||||||
@ -1020,8 +1027,7 @@ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
|
|||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
sta_id = priv->cfg->ops->smgmt->add_station(priv, addr, is_ap,
|
sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config);
|
||||||
0, cur_ht_config);
|
|
||||||
|
|
||||||
/* Set up default rate scaling table in device's station table */
|
/* Set up default rate scaling table in device's station table */
|
||||||
iwl_sta_init_lq(priv, addr, is_ap);
|
iwl_sta_init_lq(priv, addr, is_ap);
|
||||||
@ -1054,7 +1060,7 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
|
|||||||
|
|
||||||
/* If we are an AP, then find the station, or use BCAST */
|
/* If we are an AP, then find the station, or use BCAST */
|
||||||
case NL80211_IFTYPE_AP:
|
case NL80211_IFTYPE_AP:
|
||||||
sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1);
|
sta_id = iwl_find_station(priv, hdr->addr1);
|
||||||
if (sta_id != IWL_INVALID_STATION)
|
if (sta_id != IWL_INVALID_STATION)
|
||||||
return sta_id;
|
return sta_id;
|
||||||
return priv->hw_params.bcast_sta_id;
|
return priv->hw_params.bcast_sta_id;
|
||||||
@ -1062,13 +1068,13 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
|
|||||||
/* If this frame is going out to an IBSS network, find the station,
|
/* If this frame is going out to an IBSS network, find the station,
|
||||||
* or create a new station table entry */
|
* or create a new station table entry */
|
||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
sta_id = priv->cfg->ops->smgmt->find_station(priv, hdr->addr1);
|
sta_id = iwl_find_station(priv, hdr->addr1);
|
||||||
if (sta_id != IWL_INVALID_STATION)
|
if (sta_id != IWL_INVALID_STATION)
|
||||||
return sta_id;
|
return sta_id;
|
||||||
|
|
||||||
/* Create new station table entry */
|
/* Create new station table entry */
|
||||||
sta_id = priv->cfg->ops->smgmt->add_station(priv, hdr->addr1,
|
sta_id = iwl_add_station(priv, hdr->addr1, false,
|
||||||
0, CMD_ASYNC, NULL);
|
CMD_ASYNC, NULL);
|
||||||
|
|
||||||
if (sta_id != IWL_INVALID_STATION)
|
if (sta_id != IWL_INVALID_STATION)
|
||||||
return sta_id;
|
return sta_id;
|
||||||
@ -1111,7 +1117,7 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv,
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int sta_id;
|
int sta_id;
|
||||||
|
|
||||||
sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
|
sta_id = iwl_find_station(priv, addr);
|
||||||
if (sta_id == IWL_INVALID_STATION)
|
if (sta_id == IWL_INVALID_STATION)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
@ -1133,7 +1139,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int sta_id;
|
int sta_id;
|
||||||
|
|
||||||
sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
|
sta_id = iwl_find_station(priv, addr);
|
||||||
if (sta_id == IWL_INVALID_STATION) {
|
if (sta_id == IWL_INVALID_STATION) {
|
||||||
IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
|
IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
@ -1168,7 +1174,7 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
|
|||||||
void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
|
void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
|
||||||
{
|
{
|
||||||
/* FIXME: need locking over ps_status ??? */
|
/* FIXME: need locking over ps_status ??? */
|
||||||
u8 sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
|
u8 sta_id = iwl_find_station(priv, addr);
|
||||||
|
|
||||||
if (sta_id != IWL_INVALID_STATION) {
|
if (sta_id != IWL_INVALID_STATION) {
|
||||||
u8 sta_awake = priv->stations[sta_id].
|
u8 sta_awake = priv->stations[sta_id].
|
||||||
|
@ -51,16 +51,15 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
|
|||||||
struct ieee80211_key_conf *keyconf,
|
struct ieee80211_key_conf *keyconf,
|
||||||
const u8 *addr, u32 iv32, u16 *phase1key);
|
const u8 *addr, u32 iv32, u16 *phase1key);
|
||||||
|
|
||||||
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
|
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap);
|
||||||
int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
|
int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, bool is_ap);
|
||||||
void iwl_clear_stations_table(struct iwl_priv *priv);
|
void iwl_clear_stations_table(struct iwl_priv *priv);
|
||||||
int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
|
int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
|
||||||
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
|
int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
|
||||||
int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
|
int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
|
||||||
int iwl_send_add_sta(struct iwl_priv *priv,
|
int iwl_send_add_sta(struct iwl_priv *priv,
|
||||||
struct iwl_addsta_cmd *sta, u8 flags);
|
struct iwl_addsta_cmd *sta, u8 flags);
|
||||||
u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
|
u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
|
||||||
int is_ap, u8 flags,
|
|
||||||
struct ieee80211_sta_ht_cap *ht_info);
|
struct ieee80211_sta_ht_cap *ht_info);
|
||||||
void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
|
void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid);
|
||||||
int iwl_sta_rx_agg_start(struct iwl_priv *priv,
|
int iwl_sta_rx_agg_start(struct iwl_priv *priv,
|
||||||
|
@ -95,144 +95,6 @@ struct iwl_mod_params iwl3945_mod_params = {
|
|||||||
/* the rest are 0 by default */
|
/* the rest are 0 by default */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*************** STATION TABLE MANAGEMENT ****
|
|
||||||
* mac80211 should be examined to determine if sta_info is duplicating
|
|
||||||
* the functionality provided here
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**************************************************************/
|
|
||||||
#if 0 /* temporary disable till we add real remove station */
|
|
||||||
/**
|
|
||||||
* iwl3945_remove_station - Remove driver's knowledge of station.
|
|
||||||
*
|
|
||||||
* NOTE: This does not remove station from device's station table.
|
|
||||||
*/
|
|
||||||
static u8 iwl3945_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
|
|
||||||
{
|
|
||||||
int index = IWL_INVALID_STATION;
|
|
||||||
int i;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
|
||||||
|
|
||||||
if (is_ap)
|
|
||||||
index = IWL_AP_ID;
|
|
||||||
else if (is_broadcast_ether_addr(addr))
|
|
||||||
index = priv->hw_params.bcast_sta_id;
|
|
||||||
else
|
|
||||||
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
|
|
||||||
if (priv->stations_39[i].used &&
|
|
||||||
!compare_ether_addr(priv->stations_39[i].sta.sta.addr,
|
|
||||||
addr)) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlikely(index == IWL_INVALID_STATION))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (priv->stations_39[index].used) {
|
|
||||||
priv->stations_39[index].used = 0;
|
|
||||||
priv->num_stations--;
|
|
||||||
}
|
|
||||||
|
|
||||||
BUG_ON(priv->num_stations < 0);
|
|
||||||
|
|
||||||
out:
|
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* iwl3945_clear_stations_table - Clear the driver's station table
|
|
||||||
*
|
|
||||||
* NOTE: This does not clear or otherwise alter the device's station table.
|
|
||||||
*/
|
|
||||||
void iwl3945_clear_stations_table(struct iwl_priv *priv)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
|
||||||
|
|
||||||
priv->num_stations = 0;
|
|
||||||
memset(priv->stations_39, 0, sizeof(priv->stations_39));
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* iwl3945_add_station - Add station to station tables in driver and device
|
|
||||||
*/
|
|
||||||
u8 iwl3945_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags, struct ieee80211_sta_ht_cap *ht_info)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int index = IWL_INVALID_STATION;
|
|
||||||
struct iwl3945_station_entry *station;
|
|
||||||
unsigned long flags_spin;
|
|
||||||
u8 rate;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags_spin);
|
|
||||||
if (is_ap)
|
|
||||||
index = IWL_AP_ID;
|
|
||||||
else if (is_broadcast_ether_addr(addr))
|
|
||||||
index = priv->hw_params.bcast_sta_id;
|
|
||||||
else
|
|
||||||
for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
|
|
||||||
if (!compare_ether_addr(priv->stations_39[i].sta.sta.addr,
|
|
||||||
addr)) {
|
|
||||||
index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!priv->stations_39[i].used &&
|
|
||||||
index == IWL_INVALID_STATION)
|
|
||||||
index = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These two conditions has the same outcome but keep them separate
|
|
||||||
since they have different meaning */
|
|
||||||
if (unlikely(index == IWL_INVALID_STATION)) {
|
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->stations_39[index].used &&
|
|
||||||
!compare_ether_addr(priv->stations_39[index].sta.sta.addr, addr)) {
|
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
IWL_DEBUG_ASSOC(priv, "Add STA ID %d: %pM\n", index, addr);
|
|
||||||
station = &priv->stations_39[index];
|
|
||||||
station->used = 1;
|
|
||||||
priv->num_stations++;
|
|
||||||
|
|
||||||
/* Set up the REPLY_ADD_STA command to send to device */
|
|
||||||
memset(&station->sta, 0, sizeof(struct iwl3945_addsta_cmd));
|
|
||||||
memcpy(station->sta.sta.addr, addr, ETH_ALEN);
|
|
||||||
station->sta.mode = 0;
|
|
||||||
station->sta.sta.sta_id = index;
|
|
||||||
station->sta.station_flags = 0;
|
|
||||||
|
|
||||||
if (priv->band == IEEE80211_BAND_5GHZ)
|
|
||||||
rate = IWL_RATE_6M_PLCP;
|
|
||||||
else
|
|
||||||
rate = IWL_RATE_1M_PLCP;
|
|
||||||
|
|
||||||
/* Turn on both antennas for the station... */
|
|
||||||
station->sta.rate_n_flags =
|
|
||||||
iwl3945_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
|
|
||||||
|
|
||||||
/* Add station to device's station table */
|
|
||||||
iwl_send_add_sta(priv,
|
|
||||||
(struct iwl_addsta_cmd *)&station->sta, flags);
|
|
||||||
return index;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* iwl3945_get_antenna_flags - Get antenna flags for RXON command
|
* iwl3945_get_antenna_flags - Get antenna flags for RXON command
|
||||||
* @priv: eeprom and antenna fields are used to determine antenna flags
|
* @priv: eeprom and antenna fields are used to determine antenna flags
|
||||||
@ -289,32 +151,31 @@ static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
|
|||||||
key_flags &= ~STA_KEY_FLG_INVALID;
|
key_flags &= ~STA_KEY_FLG_INVALID;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||||
priv->stations_39[sta_id].keyinfo.alg = keyconf->alg;
|
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
|
||||||
priv->stations_39[sta_id].keyinfo.keylen = keyconf->keylen;
|
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
|
||||||
memcpy(priv->stations_39[sta_id].keyinfo.key, keyconf->key,
|
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
|
||||||
keyconf->keylen);
|
keyconf->keylen);
|
||||||
|
|
||||||
memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key,
|
memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
|
||||||
keyconf->keylen);
|
keyconf->keylen);
|
||||||
|
|
||||||
if ((priv->stations_39[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
|
if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
|
||||||
== STA_KEY_FLG_NO_ENC)
|
== STA_KEY_FLG_NO_ENC)
|
||||||
priv->stations_39[sta_id].sta.key.key_offset =
|
priv->stations[sta_id].sta.key.key_offset =
|
||||||
iwl_get_free_ucode_key_index(priv);
|
iwl_get_free_ucode_key_index(priv);
|
||||||
/* else, we are overriding an existing key => no need to allocated room
|
/* else, we are overriding an existing key => no need to allocated room
|
||||||
* in uCode. */
|
* in uCode. */
|
||||||
|
|
||||||
WARN(priv->stations_39[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
|
WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
|
||||||
"no space for a new key");
|
"no space for a new key");
|
||||||
|
|
||||||
priv->stations_39[sta_id].sta.key.key_flags = key_flags;
|
priv->stations[sta_id].sta.key.key_flags = key_flags;
|
||||||
priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||||
priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||||
|
|
||||||
IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n");
|
IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n");
|
||||||
|
|
||||||
ret = iwl_send_add_sta(priv,
|
ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
|
||||||
(struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, CMD_ASYNC);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||||
|
|
||||||
@ -340,17 +201,16 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->sta_lock, flags);
|
spin_lock_irqsave(&priv->sta_lock, flags);
|
||||||
memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
|
memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
|
||||||
memset(&priv->stations_39[sta_id].sta.key, 0,
|
memset(&priv->stations[sta_id].sta.key, 0,
|
||||||
sizeof(struct iwl4965_keyinfo));
|
sizeof(struct iwl4965_keyinfo));
|
||||||
priv->stations_39[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
|
priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
|
||||||
priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
|
||||||
priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
|
||||||
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
spin_unlock_irqrestore(&priv->sta_lock, flags);
|
||||||
|
|
||||||
IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n");
|
IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n");
|
||||||
iwl_send_add_sta(priv,
|
iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0);
|
||||||
(struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, 0);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,7 +438,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
|
|||||||
int sta_id)
|
int sta_id)
|
||||||
{
|
{
|
||||||
struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
|
struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
|
||||||
struct iwl_hw_key *keyinfo = &priv->stations_39[sta_id].keyinfo;
|
struct iwl_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;
|
||||||
|
|
||||||
switch (keyinfo->alg) {
|
switch (keyinfo->alg) {
|
||||||
case ALG_CCMP:
|
case ALG_CCMP:
|
||||||
@ -753,7 +613,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||||||
if (ieee80211_is_data_qos(fc)) {
|
if (ieee80211_is_data_qos(fc)) {
|
||||||
qc = ieee80211_get_qos_ctl(hdr);
|
qc = ieee80211_get_qos_ctl(hdr);
|
||||||
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
|
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
|
||||||
seq_number = priv->stations_39[sta_id].tid[tid].seq_number &
|
seq_number = priv->stations[sta_id].tid[tid].seq_number &
|
||||||
IEEE80211_SCTL_SEQ;
|
IEEE80211_SCTL_SEQ;
|
||||||
hdr->seq_ctrl = cpu_to_le16(seq_number) |
|
hdr->seq_ctrl = cpu_to_le16(seq_number) |
|
||||||
(hdr->seq_ctrl &
|
(hdr->seq_ctrl &
|
||||||
@ -813,7 +673,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
|
|||||||
if (!ieee80211_has_morefrags(hdr->frame_control)) {
|
if (!ieee80211_has_morefrags(hdr->frame_control)) {
|
||||||
txq->need_update = 1;
|
txq->need_update = 1;
|
||||||
if (qc)
|
if (qc)
|
||||||
priv->stations_39[sta_id].tid[tid].seq_number = seq_number;
|
priv->stations[sta_id].tid[tid].seq_number = seq_number;
|
||||||
} else {
|
} else {
|
||||||
wait_write_ptr = 1;
|
wait_write_ptr = 1;
|
||||||
txq->need_update = 0;
|
txq->need_update = 0;
|
||||||
@ -1316,7 +1176,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
|
|||||||
|
|
||||||
/* If we've added more space for the firmware to place data, tell it.
|
/* If we've added more space for the firmware to place data, tell it.
|
||||||
* Increment device's write pointer in multiples of 8. */
|
* Increment device's write pointer in multiples of 8. */
|
||||||
if ((write != (rxq->write & ~0x7))
|
if ((rxq->write_actual != (rxq->write & ~0x7))
|
||||||
|| (abs(rxq->write - rxq->read) > 7)) {
|
|| (abs(rxq->write - rxq->read) > 7)) {
|
||||||
spin_lock_irqsave(&rxq->lock, flags);
|
spin_lock_irqsave(&rxq->lock, flags);
|
||||||
rxq->need_update = 1;
|
rxq->need_update = 1;
|
||||||
@ -1337,7 +1197,7 @@ static int iwl3945_rx_queue_restock(struct iwl_priv *priv)
|
|||||||
* Also restock the Rx queue via iwl3945_rx_queue_restock.
|
* Also restock the Rx queue via iwl3945_rx_queue_restock.
|
||||||
* This is called as a scheduled work item (except for during initialization)
|
* This is called as a scheduled work item (except for during initialization)
|
||||||
*/
|
*/
|
||||||
static void iwl3945_rx_allocate(struct iwl_priv *priv)
|
static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
|
||||||
{
|
{
|
||||||
struct iwl_rx_queue *rxq = &priv->rxq;
|
struct iwl_rx_queue *rxq = &priv->rxq;
|
||||||
struct list_head *element;
|
struct list_head *element;
|
||||||
@ -1360,7 +1220,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv)
|
|||||||
/* Alloc a new receive buffer */
|
/* Alloc a new receive buffer */
|
||||||
rxb->skb =
|
rxb->skb =
|
||||||
alloc_skb(priv->hw_params.rx_buf_size,
|
alloc_skb(priv->hw_params.rx_buf_size,
|
||||||
GFP_KERNEL);
|
priority);
|
||||||
if (!rxb->skb) {
|
if (!rxb->skb) {
|
||||||
if (net_ratelimit())
|
if (net_ratelimit())
|
||||||
IWL_CRIT(priv, ": Can not allocate SKB buffers\n");
|
IWL_CRIT(priv, ": Can not allocate SKB buffers\n");
|
||||||
@ -1419,6 +1279,7 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
|
|||||||
* not restocked the Rx queue with fresh buffers */
|
* not restocked the Rx queue with fresh buffers */
|
||||||
rxq->read = rxq->write = 0;
|
rxq->read = rxq->write = 0;
|
||||||
rxq->free_count = 0;
|
rxq->free_count = 0;
|
||||||
|
rxq->write_actual = 0;
|
||||||
spin_unlock_irqrestore(&rxq->lock, flags);
|
spin_unlock_irqrestore(&rxq->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1427,13 +1288,21 @@ void iwl3945_rx_replenish(void *data)
|
|||||||
struct iwl_priv *priv = data;
|
struct iwl_priv *priv = data;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
iwl3945_rx_allocate(priv);
|
iwl3945_rx_allocate(priv, GFP_KERNEL);
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
spin_lock_irqsave(&priv->lock, flags);
|
||||||
iwl3945_rx_queue_restock(priv);
|
iwl3945_rx_queue_restock(priv);
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
spin_unlock_irqrestore(&priv->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void iwl3945_rx_replenish_now(struct iwl_priv *priv)
|
||||||
|
{
|
||||||
|
iwl3945_rx_allocate(priv, GFP_ATOMIC);
|
||||||
|
|
||||||
|
iwl3945_rx_queue_restock(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
|
/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
|
||||||
* If an SKB has been detached, the POOL needs to have its SKB set to NULL
|
* If an SKB has been detached, the POOL needs to have its SKB set to NULL
|
||||||
* This free routine walks the list of POOL entries and if SKB is set to
|
* This free routine walks the list of POOL entries and if SKB is set to
|
||||||
@ -1556,13 +1425,19 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u8 fill_rx = 0;
|
u8 fill_rx = 0;
|
||||||
u32 count = 8;
|
u32 count = 8;
|
||||||
|
int total_empty = 0;
|
||||||
|
|
||||||
/* uCode's read index (stored in shared DRAM) indicates the last Rx
|
/* uCode's read index (stored in shared DRAM) indicates the last Rx
|
||||||
* buffer that the driver may process (last buffer filled by ucode). */
|
* buffer that the driver may process (last buffer filled by ucode). */
|
||||||
r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF;
|
r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF;
|
||||||
i = rxq->read;
|
i = rxq->read;
|
||||||
|
|
||||||
if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2))
|
/* calculate total frames need to be restock after handling RX */
|
||||||
|
total_empty = r - priv->rxq.write_actual;
|
||||||
|
if (total_empty < 0)
|
||||||
|
total_empty += RX_QUEUE_SIZE;
|
||||||
|
|
||||||
|
if (total_empty > (RX_QUEUE_SIZE / 2))
|
||||||
fill_rx = 1;
|
fill_rx = 1;
|
||||||
/* Rx interrupt, but nothing sent from uCode */
|
/* Rx interrupt, but nothing sent from uCode */
|
||||||
if (i == r)
|
if (i == r)
|
||||||
@ -1639,7 +1514,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
|
|||||||
count++;
|
count++;
|
||||||
if (count >= 8) {
|
if (count >= 8) {
|
||||||
priv->rxq.read = i;
|
priv->rxq.read = i;
|
||||||
iwl3945_rx_queue_restock(priv);
|
iwl3945_rx_replenish_now(priv);
|
||||||
count = 0;
|
count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1647,7 +1522,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
|
|||||||
|
|
||||||
/* Backtrack one entry */
|
/* Backtrack one entry */
|
||||||
priv->rxq.read = i;
|
priv->rxq.read = i;
|
||||||
iwl3945_rx_queue_restock(priv);
|
if (fill_rx)
|
||||||
|
iwl3945_rx_replenish_now(priv);
|
||||||
|
else
|
||||||
|
iwl3945_rx_queue_restock(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call this function to flush any scheduled tasklet */
|
/* call this function to flush any scheduled tasklet */
|
||||||
@ -2589,7 +2467,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
|
|||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
rfkill = iwl_read_prph(priv, APMG_RFKILL_REG);
|
rfkill = iwl_read_prph(priv, APMG_RFKILL_REG);
|
||||||
IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill);
|
IWL_DEBUG_INFO(priv, "RFKILL status: 0x%x\n", rfkill);
|
||||||
@ -2681,7 +2559,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
|
|||||||
set_bit(STATUS_EXIT_PENDING, &priv->status);
|
set_bit(STATUS_EXIT_PENDING, &priv->status);
|
||||||
|
|
||||||
iwl3945_led_unregister(priv);
|
iwl3945_led_unregister(priv);
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
/* Unblock any waiting calls */
|
/* Unblock any waiting calls */
|
||||||
wake_up_interruptible_all(&priv->wait_command_queue);
|
wake_up_interruptible_all(&priv->wait_command_queue);
|
||||||
@ -2833,7 +2711,7 @@ static int __iwl3945_up(struct iwl_priv *priv)
|
|||||||
|
|
||||||
for (i = 0; i < MAX_HW_RESTARTS; i++) {
|
for (i = 0; i < MAX_HW_RESTARTS; i++) {
|
||||||
|
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
/* load bootstrap state machine,
|
/* load bootstrap state machine,
|
||||||
* load bootstrap program into processor's memory,
|
* load bootstrap program into processor's memory,
|
||||||
@ -3247,7 +3125,7 @@ void iwl3945_post_associate(struct iwl_priv *priv)
|
|||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
|
|
||||||
priv->assoc_id = 1;
|
priv->assoc_id = 1;
|
||||||
priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 0, 0, NULL);
|
iwl_add_station(priv, priv->bssid, 0, CMD_SYNC, NULL);
|
||||||
iwl3945_sync_sta(priv, IWL_STA_ID,
|
iwl3945_sync_sta(priv, IWL_STA_ID,
|
||||||
(priv->band == IEEE80211_BAND_5GHZ) ?
|
(priv->band == IEEE80211_BAND_5GHZ) ?
|
||||||
IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
|
IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
|
||||||
@ -3438,7 +3316,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
|
|||||||
/* restore RXON assoc */
|
/* restore RXON assoc */
|
||||||
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
|
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
|
||||||
iwlcore_commit_rxon(priv);
|
iwlcore_commit_rxon(priv);
|
||||||
priv->cfg->ops->smgmt->add_station(priv, iwl_bcast_addr, 0, 0, NULL);
|
iwl_add_station(priv, iwl_bcast_addr, 0, CMD_SYNC, NULL);
|
||||||
}
|
}
|
||||||
iwl3945_send_beacon_cmd(priv);
|
iwl3945_send_beacon_cmd(priv);
|
||||||
|
|
||||||
@ -3469,7 +3347,7 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
|||||||
static_key = !iwl_is_associated(priv);
|
static_key = !iwl_is_associated(priv);
|
||||||
|
|
||||||
if (!static_key) {
|
if (!static_key) {
|
||||||
sta_id = priv->cfg->ops->smgmt->find_station(priv, addr);
|
sta_id = iwl_find_station(priv, addr);
|
||||||
if (sta_id == IWL_INVALID_STATION) {
|
if (sta_id == IWL_INVALID_STATION) {
|
||||||
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
|
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
|
||||||
addr);
|
addr);
|
||||||
@ -4044,7 +3922,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
|
|||||||
mutex_init(&priv->mutex);
|
mutex_init(&priv->mutex);
|
||||||
|
|
||||||
/* Clear the driver's (not device's) station table */
|
/* Clear the driver's (not device's) station table */
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
priv->data_retry_limit = -1;
|
priv->data_retry_limit = -1;
|
||||||
priv->ieee_channels = NULL;
|
priv->ieee_channels = NULL;
|
||||||
@ -4407,7 +4285,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
|
|||||||
iwl3945_hw_txq_ctx_free(priv);
|
iwl3945_hw_txq_ctx_free(priv);
|
||||||
|
|
||||||
iwl3945_unset_hw_params(priv);
|
iwl3945_unset_hw_params(priv);
|
||||||
priv->cfg->ops->smgmt->clear_station_table(priv);
|
iwl_clear_stations_table(priv);
|
||||||
|
|
||||||
/*netif_stop_queue(dev); */
|
/*netif_stop_queue(dev); */
|
||||||
flush_workqueue(priv->workqueue);
|
flush_workqueue(priv->workqueue);
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
config IWM
|
config IWM
|
||||||
tristate "Intel Wireless Multicomm 3200 WiFi driver"
|
tristate "Intel Wireless Multicomm 3200 WiFi driver"
|
||||||
depends on MMC && WLAN_80211 && EXPERIMENTAL
|
depends on MMC && WLAN_80211 && EXPERIMENTAL
|
||||||
|
depends on CFG80211
|
||||||
select WIRELESS_EXT
|
select WIRELESS_EXT
|
||||||
select CFG80211
|
|
||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
select RFKILL
|
|
||||||
|
|
||||||
config IWM_DEBUG
|
config IWM_DEBUG
|
||||||
bool "Enable full debugging output in iwmc3200wifi"
|
bool "Enable full debugging output in iwmc3200wifi"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
obj-$(CONFIG_IWM) := iwmc3200wifi.o
|
obj-$(CONFIG_IWM) := iwmc3200wifi.o
|
||||||
iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
|
iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
|
||||||
iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o rfkill.o
|
iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o
|
||||||
|
|
||||||
iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o
|
iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o
|
||||||
|
@ -268,7 +268,7 @@ static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
|
|||||||
|
|
||||||
iwm->conf.frag_threshold = wiphy->frag_threshold;
|
iwm->conf.frag_threshold = wiphy->frag_threshold;
|
||||||
|
|
||||||
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
|
ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
|
||||||
CFG_FRAG_THRESHOLD,
|
CFG_FRAG_THRESHOLD,
|
||||||
iwm->conf.frag_threshold);
|
iwm->conf.frag_threshold);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -72,7 +72,7 @@ static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (fw->size < IWM_HDR_LEN) {
|
if (fw->size < IWM_HDR_LEN) {
|
||||||
IWM_ERR(iwm, "FW is too small (%d)\n", fw->size);
|
IWM_ERR(iwm, "FW is too small (%zu)\n", fw->size);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,8 +343,4 @@ int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size,
|
|||||||
struct iwm_wifi_cmd *cmd);
|
struct iwm_wifi_cmd *cmd);
|
||||||
void iwm_rx_free(struct iwm_priv *iwm);
|
void iwm_rx_free(struct iwm_priv *iwm);
|
||||||
|
|
||||||
/* RF Kill API */
|
|
||||||
int iwm_rfkill_init(struct iwm_priv *iwm);
|
|
||||||
void iwm_rfkill_exit(struct iwm_priv *iwm);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -136,17 +136,8 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
|
|||||||
|
|
||||||
wdev->netdev = ndev;
|
wdev->netdev = ndev;
|
||||||
|
|
||||||
ret = iwm_rfkill_init(iwm);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(dev, "Failed to init rfkill\n");
|
|
||||||
goto out_rfkill;
|
|
||||||
}
|
|
||||||
|
|
||||||
return iwm;
|
return iwm;
|
||||||
|
|
||||||
out_rfkill:
|
|
||||||
unregister_netdev(ndev);
|
|
||||||
|
|
||||||
out_ndev:
|
out_ndev:
|
||||||
free_netdev(ndev);
|
free_netdev(ndev);
|
||||||
|
|
||||||
@ -162,7 +153,6 @@ void iwm_if_free(struct iwm_priv *iwm)
|
|||||||
if (!iwm_to_ndev(iwm))
|
if (!iwm_to_ndev(iwm))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
iwm_rfkill_exit(iwm);
|
|
||||||
unregister_netdev(iwm_to_ndev(iwm));
|
unregister_netdev(iwm_to_ndev(iwm));
|
||||||
free_netdev(iwm_to_ndev(iwm));
|
free_netdev(iwm_to_ndev(iwm));
|
||||||
iwm_wdev_free(iwm);
|
iwm_wdev_free(iwm);
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* Intel Wireless Multicomm 3200 WiFi driver
|
|
||||||
*
|
|
||||||
* Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
|
|
||||||
* Samuel Ortiz <samuel.ortiz@intel.com>
|
|
||||||
* Zhu Yi <yi.zhu@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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/rfkill.h>
|
|
||||||
|
|
||||||
#include "iwm.h"
|
|
||||||
|
|
||||||
static int iwm_rfkill_soft_toggle(void *data, enum rfkill_state state)
|
|
||||||
{
|
|
||||||
struct iwm_priv *iwm = data;
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case RFKILL_STATE_UNBLOCKED:
|
|
||||||
if (test_bit(IWM_RADIO_RFKILL_HW, &iwm->radio))
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
if (test_and_clear_bit(IWM_RADIO_RFKILL_SW, &iwm->radio) &&
|
|
||||||
(iwm_to_ndev(iwm)->flags & IFF_UP))
|
|
||||||
iwm_up(iwm);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case RFKILL_STATE_SOFT_BLOCKED:
|
|
||||||
if (!test_and_set_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
|
|
||||||
iwm_down(iwm);
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int iwm_rfkill_init(struct iwm_priv *iwm)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
iwm->rfkill = rfkill_allocate(iwm_to_dev(iwm), RFKILL_TYPE_WLAN);
|
|
||||||
if (!iwm->rfkill) {
|
|
||||||
IWM_ERR(iwm, "Unable to allocate rfkill device\n");
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
iwm->rfkill->name = KBUILD_MODNAME;
|
|
||||||
iwm->rfkill->data = iwm;
|
|
||||||
iwm->rfkill->state = RFKILL_STATE_UNBLOCKED;
|
|
||||||
iwm->rfkill->toggle_radio = iwm_rfkill_soft_toggle;
|
|
||||||
|
|
||||||
ret = rfkill_register(iwm->rfkill);
|
|
||||||
if (ret) {
|
|
||||||
IWM_ERR(iwm, "Failed to register rfkill device\n");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
fail:
|
|
||||||
rfkill_free(iwm->rfkill);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void iwm_rfkill_exit(struct iwm_priv *iwm)
|
|
||||||
{
|
|
||||||
if (iwm->rfkill)
|
|
||||||
rfkill_unregister(iwm->rfkill);
|
|
||||||
|
|
||||||
rfkill_free(iwm->rfkill);
|
|
||||||
iwm->rfkill = NULL;
|
|
||||||
}
|
|
@ -395,7 +395,7 @@ static struct iwm_if_ops if_sdio_ops = {
|
|||||||
.debugfs_init = if_sdio_debugfs_init,
|
.debugfs_init = if_sdio_debugfs_init,
|
||||||
.debugfs_exit = if_sdio_debugfs_exit,
|
.debugfs_exit = if_sdio_debugfs_exit,
|
||||||
.umac_name = "iwmc3200wifi-umac-sdio.bin",
|
.umac_name = "iwmc3200wifi-umac-sdio.bin",
|
||||||
.calib_lmac_name = "iwmc3200wifi-lmac-calib-sdio.bin",
|
.calib_lmac_name = "iwmc3200wifi-calib-sdio.bin",
|
||||||
.lmac_name = "iwmc3200wifi-lmac-sdio.bin",
|
.lmac_name = "iwmc3200wifi-lmac-sdio.bin",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ static int generate_domain_info_11d(struct parsed_region_chan_11d
|
|||||||
lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
|
lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
|
||||||
lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
|
lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
|
||||||
COUNTRY_CODE_LEN + 1 +
|
COUNTRY_CODE_LEN + 1 +
|
||||||
sizeof(struct ieeetypes_subbandset) * nr_subband);
|
sizeof(struct ieee_subbandset) * nr_subband);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,11 +302,9 @@ done:
|
|||||||
* @param parsed_region_chan pointer to parsed_region_chan_11d
|
* @param parsed_region_chan pointer to parsed_region_chan_11d
|
||||||
* @return 0
|
* @return 0
|
||||||
*/
|
*/
|
||||||
static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
|
static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo,
|
||||||
countryinfo,
|
|
||||||
u8 band,
|
u8 band,
|
||||||
struct parsed_region_chan_11d *
|
struct parsed_region_chan_11d *parsed_region_chan)
|
||||||
parsed_region_chan)
|
|
||||||
{
|
{
|
||||||
u8 nr_subband, nrchan;
|
u8 nr_subband, nrchan;
|
||||||
u8 lastchan, firstchan;
|
u8 lastchan, firstchan;
|
||||||
@ -331,7 +329,7 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
|
|||||||
lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
|
lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
|
||||||
|
|
||||||
if ((*(countryinfo->countrycode)) == 0
|
if ((*(countryinfo->countrycode)) == 0
|
||||||
|| (countryinfo->len <= COUNTRY_CODE_LEN)) {
|
|| (countryinfo->header.len <= COUNTRY_CODE_LEN)) {
|
||||||
/* No region Info or Wrong region info: treat as No 11D info */
|
/* No region Info or Wrong region info: treat as No 11D info */
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -349,8 +347,8 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
|
|||||||
memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
|
memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
|
||||||
COUNTRY_CODE_LEN);
|
COUNTRY_CODE_LEN);
|
||||||
|
|
||||||
nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
|
nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) /
|
||||||
sizeof(struct ieeetypes_subbandset);
|
sizeof(struct ieee_subbandset);
|
||||||
|
|
||||||
for (j = 0, lastchan = 0; j < nr_subband; j++) {
|
for (j = 0, lastchan = 0; j < nr_subband; j++) {
|
||||||
|
|
||||||
@ -502,7 +500,7 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
|
|||||||
{
|
{
|
||||||
struct cmd_ds_802_11d_domain_info *pdomaininfo =
|
struct cmd_ds_802_11d_domain_info *pdomaininfo =
|
||||||
&cmd->params.domaininfo;
|
&cmd->params.domaininfo;
|
||||||
struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
|
struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
|
||||||
u8 nr_subband = priv->domainreg.nr_subband;
|
u8 nr_subband = priv->domainreg.nr_subband;
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_11D);
|
lbs_deb_enter(LBS_DEB_11D);
|
||||||
@ -524,16 +522,16 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
|
|||||||
sizeof(domain->countrycode));
|
sizeof(domain->countrycode));
|
||||||
|
|
||||||
domain->header.len =
|
domain->header.len =
|
||||||
cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
|
cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) +
|
||||||
sizeof(domain->countrycode));
|
sizeof(domain->countrycode));
|
||||||
|
|
||||||
if (nr_subband) {
|
if (nr_subband) {
|
||||||
memcpy(domain->subband, priv->domainreg.subband,
|
memcpy(domain->subband, priv->domainreg.subband,
|
||||||
nr_subband * sizeof(struct ieeetypes_subbandset));
|
nr_subband * sizeof(struct ieee_subbandset));
|
||||||
|
|
||||||
cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
|
cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
|
||||||
le16_to_cpu(domain->header.len) +
|
le16_to_cpu(domain->header.len) +
|
||||||
sizeof(struct mrvlietypesheader) +
|
sizeof(struct mrvl_ie_header) +
|
||||||
S_DS_GEN);
|
S_DS_GEN);
|
||||||
} else {
|
} else {
|
||||||
cmd->size =
|
cmd->size =
|
||||||
@ -556,7 +554,7 @@ done:
|
|||||||
int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
|
int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
|
||||||
{
|
{
|
||||||
struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
|
struct cmd_ds_802_11d_domain_info *domaininfo = &resp->params.domaininforesp;
|
||||||
struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
|
struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
|
||||||
u16 action = le16_to_cpu(domaininfo->action);
|
u16 action = le16_to_cpu(domaininfo->action);
|
||||||
s16 ret = 0;
|
s16 ret = 0;
|
||||||
u8 nr_subband = 0;
|
u8 nr_subband = 0;
|
||||||
@ -567,7 +565,7 @@ int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
|
|||||||
(int)le16_to_cpu(resp->size));
|
(int)le16_to_cpu(resp->size));
|
||||||
|
|
||||||
nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
|
nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
|
||||||
sizeof(struct ieeetypes_subbandset);
|
sizeof(struct ieee_subbandset);
|
||||||
|
|
||||||
lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
|
lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
|
||||||
|
|
||||||
|
@ -20,35 +20,36 @@
|
|||||||
struct cmd_ds_command;
|
struct cmd_ds_command;
|
||||||
|
|
||||||
/** Data structure for Country IE*/
|
/** Data structure for Country IE*/
|
||||||
struct ieeetypes_subbandset {
|
struct ieee_subbandset {
|
||||||
u8 firstchan;
|
u8 firstchan;
|
||||||
u8 nrchan;
|
u8 nrchan;
|
||||||
u8 maxtxpwr;
|
u8 maxtxpwr;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct ieeetypes_countryinfoset {
|
struct ieee_ie_country_info_set {
|
||||||
u8 element_id;
|
struct ieee_ie_header header;
|
||||||
u8 len;
|
|
||||||
u8 countrycode[COUNTRY_CODE_LEN];
|
u8 countrycode[COUNTRY_CODE_LEN];
|
||||||
struct ieeetypes_subbandset subband[1];
|
struct ieee_subbandset subband[1];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ieeetypes_countryinfofullset {
|
struct ieee_ie_country_info_full_set {
|
||||||
u8 element_id;
|
struct ieee_ie_header header;
|
||||||
u8 len;
|
|
||||||
u8 countrycode[COUNTRY_CODE_LEN];
|
u8 countrycode[COUNTRY_CODE_LEN];
|
||||||
struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
|
struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_domainparamset {
|
struct mrvl_ie_domain_param_set {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
|
|
||||||
u8 countrycode[COUNTRY_CODE_LEN];
|
u8 countrycode[COUNTRY_CODE_LEN];
|
||||||
struct ieeetypes_subbandset subband[1];
|
struct ieee_subbandset subband[1];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct cmd_ds_802_11d_domain_info {
|
struct cmd_ds_802_11d_domain_info {
|
||||||
__le16 action;
|
__le16 action;
|
||||||
struct mrvlietypes_domainparamset domain;
|
struct mrvl_ie_domain_param_set domain;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/** domain regulatory information */
|
/** domain regulatory information */
|
||||||
@ -57,7 +58,7 @@ struct lbs_802_11d_domain_reg {
|
|||||||
u8 countrycode[COUNTRY_CODE_LEN];
|
u8 countrycode[COUNTRY_CODE_LEN];
|
||||||
/** No. of subband*/
|
/** No. of subband*/
|
||||||
u8 nr_subband;
|
u8 nr_subband;
|
||||||
struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
|
struct ieee_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct chan_power_11d {
|
struct chan_power_11d {
|
||||||
|
@ -12,15 +12,14 @@
|
|||||||
#include "scan.h"
|
#include "scan.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
|
|
||||||
static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp);
|
|
||||||
|
|
||||||
static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) =
|
static const u8 bssid_any[ETH_ALEN] __attribute__ ((aligned (2))) =
|
||||||
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
|
static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
|
||||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
/* The firmware needs certain bits masked out of the beacon-derviced capability
|
/* The firmware needs the following bits masked out of the beacon-derived
|
||||||
* field when associating/joining to BSSs.
|
* capability field when associating/joining to a BSS:
|
||||||
|
* 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
|
||||||
*/
|
*/
|
||||||
#define CAPINFO_MASK (~(0xda00))
|
#define CAPINFO_MASK (~(0xda00))
|
||||||
|
|
||||||
@ -102,6 +101,295 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u8 iw_auth_to_ieee_auth(u8 auth)
|
||||||
|
{
|
||||||
|
if (auth == IW_AUTH_ALG_OPEN_SYSTEM)
|
||||||
|
return 0x00;
|
||||||
|
else if (auth == IW_AUTH_ALG_SHARED_KEY)
|
||||||
|
return 0x01;
|
||||||
|
else if (auth == IW_AUTH_ALG_LEAP)
|
||||||
|
return 0x80;
|
||||||
|
|
||||||
|
lbs_deb_join("%s: invalid auth alg 0x%X\n", __func__, auth);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function prepares the authenticate command. AUTHENTICATE only
|
||||||
|
* sets the authentication suite for future associations, as the firmware
|
||||||
|
* handles authentication internally during the ASSOCIATE command.
|
||||||
|
*
|
||||||
|
* @param priv A pointer to struct lbs_private structure
|
||||||
|
* @param bssid The peer BSSID with which to authenticate
|
||||||
|
* @param auth The authentication mode to use (from wireless.h)
|
||||||
|
*
|
||||||
|
* @return 0 or -1
|
||||||
|
*/
|
||||||
|
static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth)
|
||||||
|
{
|
||||||
|
struct cmd_ds_802_11_authenticate cmd;
|
||||||
|
int ret = -1;
|
||||||
|
DECLARE_MAC_BUF(mac);
|
||||||
|
|
||||||
|
lbs_deb_enter(LBS_DEB_JOIN);
|
||||||
|
|
||||||
|
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
|
||||||
|
memcpy(cmd.bssid, bssid, ETH_ALEN);
|
||||||
|
|
||||||
|
cmd.authtype = iw_auth_to_ieee_auth(auth);
|
||||||
|
|
||||||
|
lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
|
||||||
|
print_mac(mac, bssid), cmd.authtype);
|
||||||
|
|
||||||
|
ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
|
||||||
|
|
||||||
|
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int lbs_assoc_post(struct lbs_private *priv,
|
||||||
|
struct cmd_ds_802_11_associate_response *resp)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
union iwreq_data wrqu;
|
||||||
|
struct bss_descriptor *bss;
|
||||||
|
u16 status_code;
|
||||||
|
|
||||||
|
lbs_deb_enter(LBS_DEB_ASSOC);
|
||||||
|
|
||||||
|
if (!priv->in_progress_assoc_req) {
|
||||||
|
lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
bss = &priv->in_progress_assoc_req->bss;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Older FW versions map the IEEE 802.11 Status Code in the association
|
||||||
|
* response to the following values returned in resp->statuscode:
|
||||||
|
*
|
||||||
|
* IEEE Status Code Marvell Status Code
|
||||||
|
* 0 -> 0x0000 ASSOC_RESULT_SUCCESS
|
||||||
|
* 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||||
|
* 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||||
|
* 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||||
|
* 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
||||||
|
* others -> 0x0003 ASSOC_RESULT_REFUSED
|
||||||
|
*
|
||||||
|
* Other response codes:
|
||||||
|
* 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
|
||||||
|
* 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
|
||||||
|
* association response from the AP)
|
||||||
|
*/
|
||||||
|
|
||||||
|
status_code = le16_to_cpu(resp->statuscode);
|
||||||
|
if (priv->fwrelease < 0x09000000) {
|
||||||
|
switch (status_code) {
|
||||||
|
case 0x00:
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
lbs_deb_assoc("ASSOC_RESP: internal timer "
|
||||||
|
"expired while waiting for the AP\n");
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
lbs_deb_assoc("ASSOC_RESP: association "
|
||||||
|
"refused by AP\n");
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
lbs_deb_assoc("ASSOC_RESP: authentication "
|
||||||
|
"refused by AP\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
|
||||||
|
" unknown\n", status_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* v9+ returns the AP's association response */
|
||||||
|
lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x\n", status_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status_code) {
|
||||||
|
lbs_mac_event_disconnected(priv);
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP",
|
||||||
|
(void *) (resp + sizeof (resp->hdr)),
|
||||||
|
le16_to_cpu(resp->hdr.size) - sizeof (resp->hdr));
|
||||||
|
|
||||||
|
/* Send a Media Connected event, according to the Spec */
|
||||||
|
priv->connect_status = LBS_CONNECTED;
|
||||||
|
|
||||||
|
/* Update current SSID and BSSID */
|
||||||
|
memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
|
||||||
|
priv->curbssparams.ssid_len = bss->ssid_len;
|
||||||
|
memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
|
||||||
|
|
||||||
|
priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
|
||||||
|
priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
|
||||||
|
|
||||||
|
memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
|
||||||
|
memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
|
||||||
|
priv->nextSNRNF = 0;
|
||||||
|
priv->numSNRNF = 0;
|
||||||
|
|
||||||
|
netif_carrier_on(priv->dev);
|
||||||
|
if (!priv->tx_pending_len)
|
||||||
|
netif_wake_queue(priv->dev);
|
||||||
|
|
||||||
|
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
|
||||||
|
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||||||
|
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
|
||||||
|
|
||||||
|
done:
|
||||||
|
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function prepares an association-class command.
|
||||||
|
*
|
||||||
|
* @param priv A pointer to struct lbs_private structure
|
||||||
|
* @param assoc_req The association request describing the BSS to associate
|
||||||
|
* or reassociate with
|
||||||
|
* @param command The actual command, either CMD_802_11_ASSOCIATE or
|
||||||
|
* CMD_802_11_REASSOCIATE
|
||||||
|
*
|
||||||
|
* @return 0 or -1
|
||||||
|
*/
|
||||||
|
static int lbs_associate(struct lbs_private *priv,
|
||||||
|
struct assoc_request *assoc_req,
|
||||||
|
u16 command)
|
||||||
|
{
|
||||||
|
struct cmd_ds_802_11_associate cmd;
|
||||||
|
int ret = 0;
|
||||||
|
struct bss_descriptor *bss = &assoc_req->bss;
|
||||||
|
u8 *pos = &(cmd.iebuf[0]);
|
||||||
|
u16 tmpcap, tmplen, tmpauth;
|
||||||
|
struct mrvl_ie_ssid_param_set *ssid;
|
||||||
|
struct mrvl_ie_ds_param_set *ds;
|
||||||
|
struct mrvl_ie_cf_param_set *cf;
|
||||||
|
struct mrvl_ie_rates_param_set *rates;
|
||||||
|
struct mrvl_ie_rsn_param_set *rsn;
|
||||||
|
struct mrvl_ie_auth_type *auth;
|
||||||
|
|
||||||
|
lbs_deb_enter(LBS_DEB_ASSOC);
|
||||||
|
|
||||||
|
BUG_ON((command != CMD_802_11_ASSOCIATE) &&
|
||||||
|
(command != CMD_802_11_REASSOCIATE));
|
||||||
|
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
cmd.hdr.command = cpu_to_le16(command);
|
||||||
|
|
||||||
|
/* Fill in static fields */
|
||||||
|
memcpy(cmd.bssid, bss->bssid, ETH_ALEN);
|
||||||
|
cmd.listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
|
||||||
|
|
||||||
|
/* Capability info */
|
||||||
|
tmpcap = (bss->capability & CAPINFO_MASK);
|
||||||
|
if (bss->mode == IW_MODE_INFRA)
|
||||||
|
tmpcap |= WLAN_CAPABILITY_ESS;
|
||||||
|
cmd.capability = cpu_to_le16(tmpcap);
|
||||||
|
lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
|
||||||
|
|
||||||
|
/* SSID */
|
||||||
|
ssid = (struct mrvl_ie_ssid_param_set *) pos;
|
||||||
|
ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
|
||||||
|
tmplen = bss->ssid_len;
|
||||||
|
ssid->header.len = cpu_to_le16(tmplen);
|
||||||
|
memcpy(ssid->ssid, bss->ssid, tmplen);
|
||||||
|
pos += sizeof(ssid->header) + tmplen;
|
||||||
|
|
||||||
|
ds = (struct mrvl_ie_ds_param_set *) pos;
|
||||||
|
ds->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
|
||||||
|
ds->header.len = cpu_to_le16(1);
|
||||||
|
ds->channel = bss->phy.ds.channel;
|
||||||
|
pos += sizeof(ds->header) + 1;
|
||||||
|
|
||||||
|
cf = (struct mrvl_ie_cf_param_set *) pos;
|
||||||
|
cf->header.type = cpu_to_le16(TLV_TYPE_CF);
|
||||||
|
tmplen = sizeof(*cf) - sizeof (cf->header);
|
||||||
|
cf->header.len = cpu_to_le16(tmplen);
|
||||||
|
/* IE payload should be zeroed, firmware fills it in for us */
|
||||||
|
pos += sizeof(*cf);
|
||||||
|
|
||||||
|
rates = (struct mrvl_ie_rates_param_set *) pos;
|
||||||
|
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
|
||||||
|
memcpy(&rates->rates, &bss->rates, MAX_RATES);
|
||||||
|
tmplen = MAX_RATES;
|
||||||
|
if (get_common_rates(priv, rates->rates, &tmplen)) {
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
pos += sizeof(rates->header) + tmplen;
|
||||||
|
rates->header.len = cpu_to_le16(tmplen);
|
||||||
|
lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
|
||||||
|
|
||||||
|
/* Copy the infra. association rates into Current BSS state structure */
|
||||||
|
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
|
||||||
|
memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
|
||||||
|
|
||||||
|
/* Set MSB on basic rates as the firmware requires, but _after_
|
||||||
|
* copying to current bss rates.
|
||||||
|
*/
|
||||||
|
lbs_set_basic_rate_flags(rates->rates, tmplen);
|
||||||
|
|
||||||
|
/* Firmware v9+ indicate authentication suites as a TLV */
|
||||||
|
if (priv->fwrelease >= 0x09000000) {
|
||||||
|
DECLARE_MAC_BUF(mac);
|
||||||
|
|
||||||
|
auth = (struct mrvl_ie_auth_type *) pos;
|
||||||
|
auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
|
||||||
|
auth->header.len = cpu_to_le16(2);
|
||||||
|
tmpauth = iw_auth_to_ieee_auth(priv->secinfo.auth_mode);
|
||||||
|
auth->auth = cpu_to_le16(tmpauth);
|
||||||
|
pos += sizeof(auth->header) + 2;
|
||||||
|
|
||||||
|
lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
|
||||||
|
print_mac(mac, bss->bssid), priv->secinfo.auth_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WPA/WPA2 IEs */
|
||||||
|
if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
|
||||||
|
rsn = (struct mrvl_ie_rsn_param_set *) pos;
|
||||||
|
/* WPA_IE or WPA2_IE */
|
||||||
|
rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
|
||||||
|
tmplen = (u16) assoc_req->wpa_ie[1];
|
||||||
|
rsn->header.len = cpu_to_le16(tmplen);
|
||||||
|
memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
|
||||||
|
lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: WPA/RSN IE", (u8 *) rsn,
|
||||||
|
sizeof(rsn->header) + tmplen);
|
||||||
|
pos += sizeof(rsn->header) + tmplen;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.hdr.size = cpu_to_le16((sizeof(cmd) - sizeof(cmd.iebuf)) +
|
||||||
|
(u16)(pos - (u8 *) &cmd.iebuf));
|
||||||
|
|
||||||
|
/* update curbssparams */
|
||||||
|
priv->curbssparams.channel = bss->phy.ds.channel;
|
||||||
|
|
||||||
|
if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = lbs_cmd_with_response(priv, command, &cmd);
|
||||||
|
if (ret == 0) {
|
||||||
|
ret = lbs_assoc_post(priv,
|
||||||
|
(struct cmd_ds_802_11_associate_response *) &cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Associate to a specific BSS discovered in a scan
|
* @brief Associate to a specific BSS discovered in a scan
|
||||||
*
|
*
|
||||||
@ -110,7 +398,7 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
|
|||||||
*
|
*
|
||||||
* @return 0-success, otherwise fail
|
* @return 0-success, otherwise fail
|
||||||
*/
|
*/
|
||||||
static int lbs_associate(struct lbs_private *priv,
|
static int lbs_try_associate(struct lbs_private *priv,
|
||||||
struct assoc_request *assoc_req)
|
struct assoc_request *assoc_req)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -118,11 +406,15 @@ static int lbs_associate(struct lbs_private *priv,
|
|||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_ASSOC);
|
lbs_deb_enter(LBS_DEB_ASSOC);
|
||||||
|
|
||||||
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
|
/* FW v9 and higher indicate authentication suites as a TLV in the
|
||||||
0, CMD_OPTION_WAITFORRSP,
|
* association command, not as a separate authentication command.
|
||||||
0, assoc_req->bss.bssid);
|
*/
|
||||||
if (ret)
|
if (priv->fwrelease < 0x09000000) {
|
||||||
goto out;
|
ret = lbs_set_authentication(priv, assoc_req->bss.bssid,
|
||||||
|
priv->secinfo.auth_mode);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/* Use short preamble only when both the BSS and firmware support it */
|
/* Use short preamble only when both the BSS and firmware support it */
|
||||||
if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
|
if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
|
||||||
@ -133,14 +425,78 @@ static int lbs_associate(struct lbs_private *priv,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
|
ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
|
||||||
0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lbs_adhoc_post(struct lbs_private *priv,
|
||||||
|
struct cmd_ds_802_11_ad_hoc_result *resp)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
u16 command = le16_to_cpu(resp->hdr.command);
|
||||||
|
u16 result = le16_to_cpu(resp->hdr.result);
|
||||||
|
union iwreq_data wrqu;
|
||||||
|
struct bss_descriptor *bss;
|
||||||
|
DECLARE_SSID_BUF(ssid);
|
||||||
|
|
||||||
|
lbs_deb_enter(LBS_DEB_JOIN);
|
||||||
|
|
||||||
|
if (!priv->in_progress_assoc_req) {
|
||||||
|
lbs_deb_join("ADHOC_RESP: no in-progress association "
|
||||||
|
"request\n");
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
bss = &priv->in_progress_assoc_req->bss;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Join result code 0 --> SUCCESS
|
||||||
|
*/
|
||||||
|
if (result) {
|
||||||
|
lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
|
||||||
|
if (priv->connect_status == LBS_CONNECTED)
|
||||||
|
lbs_mac_event_disconnected(priv);
|
||||||
|
ret = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send a Media Connected event, according to the Spec */
|
||||||
|
priv->connect_status = LBS_CONNECTED;
|
||||||
|
|
||||||
|
if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
|
||||||
|
/* Update the created network descriptor with the new BSSID */
|
||||||
|
memcpy(bss->bssid, resp->bssid, ETH_ALEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the BSSID from the joined/started descriptor */
|
||||||
|
memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
|
||||||
|
|
||||||
|
/* Set the new SSID to current SSID */
|
||||||
|
memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
|
||||||
|
priv->curbssparams.ssid_len = bss->ssid_len;
|
||||||
|
|
||||||
|
netif_carrier_on(priv->dev);
|
||||||
|
if (!priv->tx_pending_len)
|
||||||
|
netif_wake_queue(priv->dev);
|
||||||
|
|
||||||
|
memset(&wrqu, 0, sizeof(wrqu));
|
||||||
|
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
|
||||||
|
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
||||||
|
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
|
||||||
|
|
||||||
|
lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
|
||||||
|
print_ssid(ssid, bss->ssid, bss->ssid_len),
|
||||||
|
priv->curbssparams.bssid,
|
||||||
|
priv->curbssparams.channel);
|
||||||
|
|
||||||
|
done:
|
||||||
|
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Join an adhoc network found in a previous scan
|
* @brief Join an adhoc network found in a previous scan
|
||||||
*
|
*
|
||||||
@ -219,11 +575,10 @@ static int lbs_adhoc_join(struct lbs_private *priv,
|
|||||||
memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
|
memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
|
||||||
memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
|
memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
|
||||||
|
|
||||||
memcpy(&cmd.bss.phyparamset, &bss->phyparamset,
|
memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set));
|
||||||
sizeof(union ieeetypes_phyparamset));
|
|
||||||
|
|
||||||
memcpy(&cmd.bss.ssparamset, &bss->ssparamset,
|
memcpy(&cmd.bss.ibss, &bss->ss.ibss,
|
||||||
sizeof(union IEEEtypes_ssparamset));
|
sizeof(struct ieee_ie_ibss_param_set));
|
||||||
|
|
||||||
cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
|
cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
|
||||||
lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
|
lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
|
||||||
@ -260,7 +615,7 @@ static int lbs_adhoc_join(struct lbs_private *priv,
|
|||||||
*/
|
*/
|
||||||
lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
|
lbs_set_basic_rate_flags(cmd.bss.rates, ratesize);
|
||||||
|
|
||||||
cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow);
|
cmd.bss.ibss.atimwindow = bss->atimwindow;
|
||||||
|
|
||||||
if (assoc_req->secinfo.wep_enabled) {
|
if (assoc_req->secinfo.wep_enabled) {
|
||||||
u16 tmp = le16_to_cpu(cmd.bss.capability);
|
u16 tmp = le16_to_cpu(cmd.bss.capability);
|
||||||
@ -287,8 +642,10 @@ static int lbs_adhoc_join(struct lbs_private *priv,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
|
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_JOIN, &cmd);
|
||||||
if (ret == 0)
|
if (ret == 0) {
|
||||||
ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd);
|
ret = lbs_adhoc_post(priv,
|
||||||
|
(struct cmd_ds_802_11_ad_hoc_result *)&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
||||||
@ -343,22 +700,24 @@ static int lbs_adhoc_start(struct lbs_private *priv,
|
|||||||
WARN_ON(!assoc_req->channel);
|
WARN_ON(!assoc_req->channel);
|
||||||
|
|
||||||
/* set Physical parameter set */
|
/* set Physical parameter set */
|
||||||
cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS;
|
cmd.ds.header.id = WLAN_EID_DS_PARAMS;
|
||||||
cmd.phyparamset.dsparamset.len = 1;
|
cmd.ds.header.len = 1;
|
||||||
cmd.phyparamset.dsparamset.currentchan = assoc_req->channel;
|
cmd.ds.channel = assoc_req->channel;
|
||||||
|
|
||||||
/* set IBSS parameter set */
|
/* set IBSS parameter set */
|
||||||
cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS;
|
cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
|
||||||
cmd.ssparamset.ibssparamset.len = 2;
|
cmd.ibss.header.len = 2;
|
||||||
cmd.ssparamset.ibssparamset.atimwindow = 0;
|
cmd.ibss.atimwindow = cpu_to_le16(0);
|
||||||
|
|
||||||
/* set capability info */
|
/* set capability info */
|
||||||
tmpcap = WLAN_CAPABILITY_IBSS;
|
tmpcap = WLAN_CAPABILITY_IBSS;
|
||||||
if (assoc_req->secinfo.wep_enabled) {
|
if (assoc_req->secinfo.wep_enabled ||
|
||||||
lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n");
|
assoc_req->secinfo.WPAenabled ||
|
||||||
|
assoc_req->secinfo.WPA2enabled) {
|
||||||
|
lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n");
|
||||||
tmpcap |= WLAN_CAPABILITY_PRIVACY;
|
tmpcap |= WLAN_CAPABILITY_PRIVACY;
|
||||||
} else
|
} else
|
||||||
lbs_deb_join("ADHOC_START: WEP disabled, setting privacy off\n");
|
lbs_deb_join("ADHOC_START: WEP disabled, privacy off\n");
|
||||||
|
|
||||||
cmd.capability = cpu_to_le16(tmpcap);
|
cmd.capability = cpu_to_le16(tmpcap);
|
||||||
|
|
||||||
@ -395,7 +754,8 @@ static int lbs_adhoc_start(struct lbs_private *priv,
|
|||||||
|
|
||||||
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
|
ret = lbs_cmd_with_response(priv, CMD_802_11_AD_HOC_START, &cmd);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd);
|
ret = lbs_adhoc_post(priv,
|
||||||
|
(struct cmd_ds_802_11_ad_hoc_result *)&cmd);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
||||||
@ -720,7 +1080,7 @@ static int assoc_helper_essid(struct lbs_private *priv,
|
|||||||
assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
|
assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
|
||||||
if (bss != NULL) {
|
if (bss != NULL) {
|
||||||
memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
|
memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
|
||||||
ret = lbs_associate(priv, assoc_req);
|
ret = lbs_try_associate(priv, assoc_req);
|
||||||
} else {
|
} else {
|
||||||
lbs_deb_assoc("SSID not found; cannot associate\n");
|
lbs_deb_assoc("SSID not found; cannot associate\n");
|
||||||
}
|
}
|
||||||
@ -772,8 +1132,9 @@ static int assoc_helper_bssid(struct lbs_private *priv,
|
|||||||
|
|
||||||
memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
|
memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
|
||||||
if (assoc_req->mode == IW_MODE_INFRA) {
|
if (assoc_req->mode == IW_MODE_INFRA) {
|
||||||
ret = lbs_associate(priv, assoc_req);
|
ret = lbs_try_associate(priv, assoc_req);
|
||||||
lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret);
|
lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n",
|
||||||
|
ret);
|
||||||
} else if (assoc_req->mode == IW_MODE_ADHOC) {
|
} else if (assoc_req->mode == IW_MODE_ADHOC) {
|
||||||
lbs_adhoc_join(priv, assoc_req);
|
lbs_adhoc_join(priv, assoc_req);
|
||||||
}
|
}
|
||||||
@ -1466,57 +1827,6 @@ struct assoc_request *lbs_get_association_request(struct lbs_private *priv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief This function prepares command of authenticate.
|
|
||||||
*
|
|
||||||
* @param priv A pointer to struct lbs_private structure
|
|
||||||
* @param cmd A pointer to cmd_ds_command structure
|
|
||||||
* @param pdata_buf Void cast of pointer to a BSSID to authenticate with
|
|
||||||
*
|
|
||||||
* @return 0 or -1
|
|
||||||
*/
|
|
||||||
int lbs_cmd_80211_authenticate(struct lbs_private *priv,
|
|
||||||
struct cmd_ds_command *cmd,
|
|
||||||
void *pdata_buf)
|
|
||||||
{
|
|
||||||
struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
|
|
||||||
int ret = -1;
|
|
||||||
u8 *bssid = pdata_buf;
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_JOIN);
|
|
||||||
|
|
||||||
cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
|
|
||||||
cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
|
|
||||||
+ S_DS_GEN);
|
|
||||||
|
|
||||||
/* translate auth mode to 802.11 defined wire value */
|
|
||||||
switch (priv->secinfo.auth_mode) {
|
|
||||||
case IW_AUTH_ALG_OPEN_SYSTEM:
|
|
||||||
pauthenticate->authtype = 0x00;
|
|
||||||
break;
|
|
||||||
case IW_AUTH_ALG_SHARED_KEY:
|
|
||||||
pauthenticate->authtype = 0x01;
|
|
||||||
break;
|
|
||||||
case IW_AUTH_ALG_LEAP:
|
|
||||||
pauthenticate->authtype = 0x80;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
lbs_deb_join("AUTH_CMD: invalid auth alg 0x%X\n",
|
|
||||||
priv->secinfo.auth_mode);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
|
|
||||||
|
|
||||||
lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
|
|
||||||
bssid, pauthenticate->authtype);
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
out:
|
|
||||||
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deauthenticate from a specific BSS
|
* @brief Deauthenticate from a specific BSS
|
||||||
*
|
*
|
||||||
@ -1550,285 +1860,3 @@ int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lbs_cmd_80211_associate(struct lbs_private *priv,
|
|
||||||
struct cmd_ds_command *cmd, void *pdata_buf)
|
|
||||||
{
|
|
||||||
struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
|
|
||||||
int ret = 0;
|
|
||||||
struct assoc_request *assoc_req = pdata_buf;
|
|
||||||
struct bss_descriptor *bss = &assoc_req->bss;
|
|
||||||
u8 *pos;
|
|
||||||
u16 tmpcap, tmplen;
|
|
||||||
struct mrvlietypes_ssidparamset *ssid;
|
|
||||||
struct mrvlietypes_phyparamset *phy;
|
|
||||||
struct mrvlietypes_ssparamset *ss;
|
|
||||||
struct mrvlietypes_ratesparamset *rates;
|
|
||||||
struct mrvlietypes_rsnparamset *rsn;
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_ASSOC);
|
|
||||||
|
|
||||||
pos = (u8 *) passo;
|
|
||||||
|
|
||||||
if (!priv) {
|
|
||||||
ret = -1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
|
|
||||||
|
|
||||||
memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
|
|
||||||
pos += sizeof(passo->peerstaaddr);
|
|
||||||
|
|
||||||
/* set the listen interval */
|
|
||||||
passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
|
|
||||||
|
|
||||||
pos += sizeof(passo->capability);
|
|
||||||
pos += sizeof(passo->listeninterval);
|
|
||||||
pos += sizeof(passo->bcnperiod);
|
|
||||||
pos += sizeof(passo->dtimperiod);
|
|
||||||
|
|
||||||
ssid = (struct mrvlietypes_ssidparamset *) pos;
|
|
||||||
ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
|
|
||||||
tmplen = bss->ssid_len;
|
|
||||||
ssid->header.len = cpu_to_le16(tmplen);
|
|
||||||
memcpy(ssid->ssid, bss->ssid, tmplen);
|
|
||||||
pos += sizeof(ssid->header) + tmplen;
|
|
||||||
|
|
||||||
phy = (struct mrvlietypes_phyparamset *) pos;
|
|
||||||
phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
|
|
||||||
tmplen = sizeof(phy->fh_ds.dsparamset);
|
|
||||||
phy->header.len = cpu_to_le16(tmplen);
|
|
||||||
memcpy(&phy->fh_ds.dsparamset,
|
|
||||||
&bss->phyparamset.dsparamset.currentchan,
|
|
||||||
tmplen);
|
|
||||||
pos += sizeof(phy->header) + tmplen;
|
|
||||||
|
|
||||||
ss = (struct mrvlietypes_ssparamset *) pos;
|
|
||||||
ss->header.type = cpu_to_le16(TLV_TYPE_CF);
|
|
||||||
tmplen = sizeof(ss->cf_ibss.cfparamset);
|
|
||||||
ss->header.len = cpu_to_le16(tmplen);
|
|
||||||
pos += sizeof(ss->header) + tmplen;
|
|
||||||
|
|
||||||
rates = (struct mrvlietypes_ratesparamset *) pos;
|
|
||||||
rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
|
|
||||||
memcpy(&rates->rates, &bss->rates, MAX_RATES);
|
|
||||||
tmplen = MAX_RATES;
|
|
||||||
if (get_common_rates(priv, rates->rates, &tmplen)) {
|
|
||||||
ret = -1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
pos += sizeof(rates->header) + tmplen;
|
|
||||||
rates->header.len = cpu_to_le16(tmplen);
|
|
||||||
lbs_deb_assoc("ASSOC_CMD: num rates %u\n", tmplen);
|
|
||||||
|
|
||||||
/* Copy the infra. association rates into Current BSS state structure */
|
|
||||||
memset(&priv->curbssparams.rates, 0, sizeof(priv->curbssparams.rates));
|
|
||||||
memcpy(&priv->curbssparams.rates, &rates->rates, tmplen);
|
|
||||||
|
|
||||||
/* Set MSB on basic rates as the firmware requires, but _after_
|
|
||||||
* copying to current bss rates.
|
|
||||||
*/
|
|
||||||
lbs_set_basic_rate_flags(rates->rates, tmplen);
|
|
||||||
|
|
||||||
if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
|
|
||||||
rsn = (struct mrvlietypes_rsnparamset *) pos;
|
|
||||||
/* WPA_IE or WPA2_IE */
|
|
||||||
rsn->header.type = cpu_to_le16((u16) assoc_req->wpa_ie[0]);
|
|
||||||
tmplen = (u16) assoc_req->wpa_ie[1];
|
|
||||||
rsn->header.len = cpu_to_le16(tmplen);
|
|
||||||
memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
|
|
||||||
lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
|
|
||||||
sizeof(rsn->header) + tmplen);
|
|
||||||
pos += sizeof(rsn->header) + tmplen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update curbssparams */
|
|
||||||
priv->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
|
|
||||||
|
|
||||||
if (lbs_parse_dnld_countryinfo_11d(priv, bss)) {
|
|
||||||
ret = -1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
|
|
||||||
|
|
||||||
/* set the capability info */
|
|
||||||
tmpcap = (bss->capability & CAPINFO_MASK);
|
|
||||||
if (bss->mode == IW_MODE_INFRA)
|
|
||||||
tmpcap |= WLAN_CAPABILITY_ESS;
|
|
||||||
passo->capability = cpu_to_le16(tmpcap);
|
|
||||||
lbs_deb_assoc("ASSOC_CMD: capability 0x%04x\n", tmpcap);
|
|
||||||
|
|
||||||
done:
|
|
||||||
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lbs_ret_80211_associate(struct lbs_private *priv,
|
|
||||||
struct cmd_ds_command *resp)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
union iwreq_data wrqu;
|
|
||||||
struct ieeetypes_assocrsp *passocrsp;
|
|
||||||
struct bss_descriptor *bss;
|
|
||||||
u16 status_code;
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_ASSOC);
|
|
||||||
|
|
||||||
if (!priv->in_progress_assoc_req) {
|
|
||||||
lbs_deb_assoc("ASSOC_RESP: no in-progress assoc request\n");
|
|
||||||
ret = -1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
bss = &priv->in_progress_assoc_req->bss;
|
|
||||||
|
|
||||||
passocrsp = (struct ieeetypes_assocrsp *) &resp->params;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Older FW versions map the IEEE 802.11 Status Code in the association
|
|
||||||
* response to the following values returned in passocrsp->statuscode:
|
|
||||||
*
|
|
||||||
* IEEE Status Code Marvell Status Code
|
|
||||||
* 0 -> 0x0000 ASSOC_RESULT_SUCCESS
|
|
||||||
* 13 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
|
||||||
* 14 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
|
||||||
* 15 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
|
||||||
* 16 -> 0x0004 ASSOC_RESULT_AUTH_REFUSED
|
|
||||||
* others -> 0x0003 ASSOC_RESULT_REFUSED
|
|
||||||
*
|
|
||||||
* Other response codes:
|
|
||||||
* 0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
|
|
||||||
* 0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
|
|
||||||
* association response from the AP)
|
|
||||||
*/
|
|
||||||
|
|
||||||
status_code = le16_to_cpu(passocrsp->statuscode);
|
|
||||||
switch (status_code) {
|
|
||||||
case 0x00:
|
|
||||||
break;
|
|
||||||
case 0x01:
|
|
||||||
lbs_deb_assoc("ASSOC_RESP: invalid parameters\n");
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
lbs_deb_assoc("ASSOC_RESP: internal timer "
|
|
||||||
"expired while waiting for the AP\n");
|
|
||||||
break;
|
|
||||||
case 0x03:
|
|
||||||
lbs_deb_assoc("ASSOC_RESP: association "
|
|
||||||
"refused by AP\n");
|
|
||||||
break;
|
|
||||||
case 0x04:
|
|
||||||
lbs_deb_assoc("ASSOC_RESP: authentication "
|
|
||||||
"refused by AP\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
lbs_deb_assoc("ASSOC_RESP: failure reason 0x%02x "
|
|
||||||
" unknown\n", status_code);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status_code) {
|
|
||||||
lbs_mac_event_disconnected(priv);
|
|
||||||
ret = -1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
lbs_deb_hex(LBS_DEB_ASSOC, "ASSOC_RESP", (void *)&resp->params,
|
|
||||||
le16_to_cpu(resp->size) - S_DS_GEN);
|
|
||||||
|
|
||||||
/* Send a Media Connected event, according to the Spec */
|
|
||||||
priv->connect_status = LBS_CONNECTED;
|
|
||||||
|
|
||||||
/* Update current SSID and BSSID */
|
|
||||||
memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
|
|
||||||
priv->curbssparams.ssid_len = bss->ssid_len;
|
|
||||||
memcpy(priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
|
|
||||||
|
|
||||||
priv->SNR[TYPE_RXPD][TYPE_AVG] = 0;
|
|
||||||
priv->NF[TYPE_RXPD][TYPE_AVG] = 0;
|
|
||||||
|
|
||||||
memset(priv->rawSNR, 0x00, sizeof(priv->rawSNR));
|
|
||||||
memset(priv->rawNF, 0x00, sizeof(priv->rawNF));
|
|
||||||
priv->nextSNRNF = 0;
|
|
||||||
priv->numSNRNF = 0;
|
|
||||||
|
|
||||||
netif_carrier_on(priv->dev);
|
|
||||||
if (!priv->tx_pending_len)
|
|
||||||
netif_wake_queue(priv->dev);
|
|
||||||
|
|
||||||
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
|
|
||||||
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
|
||||||
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
|
|
||||||
|
|
||||||
done:
|
|
||||||
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
u16 command = le16_to_cpu(resp->command);
|
|
||||||
u16 result = le16_to_cpu(resp->result);
|
|
||||||
struct cmd_ds_802_11_ad_hoc_result *adhoc_resp;
|
|
||||||
union iwreq_data wrqu;
|
|
||||||
struct bss_descriptor *bss;
|
|
||||||
DECLARE_SSID_BUF(ssid);
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_JOIN);
|
|
||||||
|
|
||||||
adhoc_resp = (struct cmd_ds_802_11_ad_hoc_result *) resp;
|
|
||||||
|
|
||||||
if (!priv->in_progress_assoc_req) {
|
|
||||||
lbs_deb_join("ADHOC_RESP: no in-progress association "
|
|
||||||
"request\n");
|
|
||||||
ret = -1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
bss = &priv->in_progress_assoc_req->bss;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Join result code 0 --> SUCCESS
|
|
||||||
*/
|
|
||||||
if (result) {
|
|
||||||
lbs_deb_join("ADHOC_RESP: failed (result 0x%X)\n", result);
|
|
||||||
if (priv->connect_status == LBS_CONNECTED)
|
|
||||||
lbs_mac_event_disconnected(priv);
|
|
||||||
ret = -1;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send a Media Connected event, according to the Spec */
|
|
||||||
priv->connect_status = LBS_CONNECTED;
|
|
||||||
|
|
||||||
if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
|
|
||||||
/* Update the created network descriptor with the new BSSID */
|
|
||||||
memcpy(bss->bssid, adhoc_resp->bssid, ETH_ALEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the BSSID from the joined/started descriptor */
|
|
||||||
memcpy(&priv->curbssparams.bssid, bss->bssid, ETH_ALEN);
|
|
||||||
|
|
||||||
/* Set the new SSID to current SSID */
|
|
||||||
memcpy(&priv->curbssparams.ssid, &bss->ssid, IW_ESSID_MAX_SIZE);
|
|
||||||
priv->curbssparams.ssid_len = bss->ssid_len;
|
|
||||||
|
|
||||||
netif_carrier_on(priv->dev);
|
|
||||||
if (!priv->tx_pending_len)
|
|
||||||
netif_wake_queue(priv->dev);
|
|
||||||
|
|
||||||
memset(&wrqu, 0, sizeof(wrqu));
|
|
||||||
memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN);
|
|
||||||
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
|
|
||||||
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
|
|
||||||
|
|
||||||
lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n",
|
|
||||||
print_ssid(ssid, bss->ssid, bss->ssid_len),
|
|
||||||
priv->curbssparams.bssid,
|
|
||||||
priv->curbssparams.channel);
|
|
||||||
|
|
||||||
done:
|
|
||||||
lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -8,22 +8,9 @@
|
|||||||
void lbs_association_worker(struct work_struct *work);
|
void lbs_association_worker(struct work_struct *work);
|
||||||
struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
|
struct assoc_request *lbs_get_association_request(struct lbs_private *priv);
|
||||||
|
|
||||||
struct cmd_ds_command;
|
|
||||||
int lbs_cmd_80211_authenticate(struct lbs_private *priv,
|
|
||||||
struct cmd_ds_command *cmd,
|
|
||||||
void *pdata_buf);
|
|
||||||
|
|
||||||
int lbs_adhoc_stop(struct lbs_private *priv);
|
int lbs_adhoc_stop(struct lbs_private *priv);
|
||||||
|
|
||||||
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
|
int lbs_cmd_80211_deauthenticate(struct lbs_private *priv,
|
||||||
u8 bssid[ETH_ALEN], u16 reason);
|
u8 bssid[ETH_ALEN], u16 reason);
|
||||||
int lbs_cmd_80211_associate(struct lbs_private *priv,
|
|
||||||
struct cmd_ds_command *cmd,
|
|
||||||
void *pdata_buf);
|
|
||||||
|
|
||||||
int lbs_ret_80211_ad_hoc_start(struct lbs_private *priv,
|
|
||||||
struct cmd_ds_command *resp);
|
|
||||||
int lbs_ret_80211_associate(struct lbs_private *priv,
|
|
||||||
struct cmd_ds_command *resp);
|
|
||||||
|
|
||||||
#endif /* _LBS_ASSOC_H */
|
#endif /* _LBS_ASSOC_H */
|
||||||
|
@ -1220,8 +1220,7 @@ static void lbs_submit_command(struct lbs_private *priv,
|
|||||||
command = le16_to_cpu(cmd->command);
|
command = le16_to_cpu(cmd->command);
|
||||||
|
|
||||||
/* These commands take longer */
|
/* These commands take longer */
|
||||||
if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
|
if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
|
||||||
command == CMD_802_11_AUTHENTICATE)
|
|
||||||
timeo = 5 * HZ;
|
timeo = 5 * HZ;
|
||||||
|
|
||||||
lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
|
lbs_deb_cmd("DNLD_CMD: command 0x%04x, seq %d, size %d\n",
|
||||||
@ -1415,15 +1414,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
|
|||||||
ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
|
ret = lbs_cmd_802_11_ps_mode(cmdptr, cmd_action);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_802_11_ASSOCIATE:
|
|
||||||
case CMD_802_11_REASSOCIATE:
|
|
||||||
ret = lbs_cmd_80211_associate(priv, cmdptr, pdata_buf);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMD_802_11_AUTHENTICATE:
|
|
||||||
ret = lbs_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMD_MAC_REG_ACCESS:
|
case CMD_MAC_REG_ACCESS:
|
||||||
case CMD_BBP_REG_ACCESS:
|
case CMD_BBP_REG_ACCESS:
|
||||||
case CMD_RF_REG_ACCESS:
|
case CMD_RF_REG_ACCESS:
|
||||||
@ -1470,8 +1460,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
|
|||||||
break;
|
break;
|
||||||
case CMD_802_11_LED_GPIO_CTRL:
|
case CMD_802_11_LED_GPIO_CTRL:
|
||||||
{
|
{
|
||||||
struct mrvlietypes_ledgpio *gpio =
|
struct mrvl_ie_ledgpio *gpio =
|
||||||
(struct mrvlietypes_ledgpio*)
|
(struct mrvl_ie_ledgpio*)
|
||||||
cmdptr->params.ledgpio.data;
|
cmdptr->params.ledgpio.data;
|
||||||
|
|
||||||
memmove(&cmdptr->params.ledgpio,
|
memmove(&cmdptr->params.ledgpio,
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/if_arp.h>
|
#include <linux/if_arp.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
|
#include <asm/unaligned.h>
|
||||||
#include <net/iw_handler.h>
|
#include <net/iw_handler.h>
|
||||||
|
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
@ -154,11 +154,11 @@ static int lbs_ret_802_11_rssi(struct lbs_private *priv,
|
|||||||
lbs_deb_enter(LBS_DEB_CMD);
|
lbs_deb_enter(LBS_DEB_CMD);
|
||||||
|
|
||||||
/* store the non average value */
|
/* store the non average value */
|
||||||
priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
|
priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
|
||||||
priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
|
priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor);
|
||||||
|
|
||||||
priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
|
priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
|
||||||
priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
|
priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor);
|
||||||
|
|
||||||
priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
|
priv->RSSI[TYPE_BEACON][TYPE_NOAVG] =
|
||||||
CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
|
CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],
|
||||||
@ -210,12 +210,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
|
|||||||
ret = lbs_ret_reg_access(priv, respcmd, resp);
|
ret = lbs_ret_reg_access(priv, respcmd, resp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_RET_802_11_ASSOCIATE:
|
|
||||||
case CMD_RET(CMD_802_11_ASSOCIATE):
|
|
||||||
case CMD_RET(CMD_802_11_REASSOCIATE):
|
|
||||||
ret = lbs_ret_80211_associate(priv, resp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CMD_RET(CMD_802_11_SET_AFC):
|
case CMD_RET(CMD_802_11_SET_AFC):
|
||||||
case CMD_RET(CMD_802_11_GET_AFC):
|
case CMD_RET(CMD_802_11_GET_AFC):
|
||||||
spin_lock_irqsave(&priv->driver_lock, flags);
|
spin_lock_irqsave(&priv->driver_lock, flags);
|
||||||
@ -225,7 +219,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CMD_RET(CMD_802_11_AUTHENTICATE):
|
|
||||||
case CMD_RET(CMD_802_11_BEACON_STOP):
|
case CMD_RET(CMD_802_11_BEACON_STOP):
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -183,12 +183,12 @@ out_unlock:
|
|||||||
*/
|
*/
|
||||||
static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
|
static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
|
||||||
{
|
{
|
||||||
struct mrvlietypesheader *tlv_h;
|
struct mrvl_ie_header *tlv_h;
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
ssize_t pos = 0;
|
ssize_t pos = 0;
|
||||||
|
|
||||||
while (pos < size) {
|
while (pos < size) {
|
||||||
tlv_h = (struct mrvlietypesheader *) tlv;
|
tlv_h = (struct mrvl_ie_header *) tlv;
|
||||||
if (!tlv_h->len)
|
if (!tlv_h->len)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (tlv_h->type == cpu_to_le16(tlv_type))
|
if (tlv_h->type == cpu_to_le16(tlv_type))
|
||||||
@ -206,7 +206,7 @@ static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
|
|||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct cmd_ds_802_11_subscribe_event *subscribed;
|
struct cmd_ds_802_11_subscribe_event *subscribed;
|
||||||
struct mrvlietypes_thresholds *got;
|
struct mrvl_ie_thresholds *got;
|
||||||
struct lbs_private *priv = file->private_data;
|
struct lbs_private *priv = file->private_data;
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
@ -259,7 +259,7 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
|
|||||||
loff_t *ppos)
|
loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct cmd_ds_802_11_subscribe_event *events;
|
struct cmd_ds_802_11_subscribe_event *events;
|
||||||
struct mrvlietypes_thresholds *tlv;
|
struct mrvl_ie_thresholds *tlv;
|
||||||
struct lbs_private *priv = file->private_data;
|
struct lbs_private *priv = file->private_data;
|
||||||
ssize_t buf_size;
|
ssize_t buf_size;
|
||||||
int value, freq, new_mask;
|
int value, freq, new_mask;
|
||||||
|
@ -321,8 +321,6 @@ struct lbs_private {
|
|||||||
|
|
||||||
u32 monitormode;
|
u32 monitormode;
|
||||||
u8 fw_ready;
|
u8 fw_ready;
|
||||||
u8 fn_init_required;
|
|
||||||
u8 fn_shutdown_required;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct cmd_confirm_sleep confirm_sleep;
|
extern struct cmd_confirm_sleep confirm_sleep;
|
||||||
@ -340,7 +338,7 @@ struct bss_descriptor {
|
|||||||
u32 rssi;
|
u32 rssi;
|
||||||
u32 channel;
|
u32 channel;
|
||||||
u16 beaconperiod;
|
u16 beaconperiod;
|
||||||
u32 atimwindow;
|
__le16 atimwindow;
|
||||||
|
|
||||||
/* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
|
/* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
|
||||||
u8 mode;
|
u8 mode;
|
||||||
@ -350,10 +348,10 @@ struct bss_descriptor {
|
|||||||
|
|
||||||
unsigned long last_scanned;
|
unsigned long last_scanned;
|
||||||
|
|
||||||
union ieeetypes_phyparamset phyparamset;
|
union ieee_phy_param_set phy;
|
||||||
union IEEEtypes_ssparamset ssparamset;
|
union ieee_ss_param_set ss;
|
||||||
|
|
||||||
struct ieeetypes_countryinfofullset countryinfo;
|
struct ieee_ie_country_info_full_set countryinfo;
|
||||||
|
|
||||||
u8 wpa_ie[MAX_WPA_IE_LEN];
|
u8 wpa_ie[MAX_WPA_IE_LEN];
|
||||||
size_t wpa_ie_len;
|
size_t wpa_ie_len;
|
||||||
|
@ -250,7 +250,9 @@ struct cmd_ds_gspi_bus_config {
|
|||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct cmd_ds_802_11_authenticate {
|
struct cmd_ds_802_11_authenticate {
|
||||||
u8 macaddr[ETH_ALEN];
|
struct cmd_header hdr;
|
||||||
|
|
||||||
|
u8 bssid[ETH_ALEN];
|
||||||
u8 authtype;
|
u8 authtype;
|
||||||
u8 reserved[10];
|
u8 reserved[10];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
@ -263,22 +265,23 @@ struct cmd_ds_802_11_deauthenticate {
|
|||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct cmd_ds_802_11_associate {
|
struct cmd_ds_802_11_associate {
|
||||||
u8 peerstaaddr[6];
|
struct cmd_header hdr;
|
||||||
|
|
||||||
|
u8 bssid[6];
|
||||||
__le16 capability;
|
__le16 capability;
|
||||||
__le16 listeninterval;
|
__le16 listeninterval;
|
||||||
__le16 bcnperiod;
|
__le16 bcnperiod;
|
||||||
u8 dtimperiod;
|
u8 dtimperiod;
|
||||||
|
u8 iebuf[512]; /* Enough for required and most optional IEs */
|
||||||
#if 0
|
|
||||||
mrvlietypes_ssidparamset_t ssidParamSet;
|
|
||||||
mrvlietypes_phyparamset_t phyparamset;
|
|
||||||
mrvlietypes_ssparamset_t ssparamset;
|
|
||||||
mrvlietypes_ratesparamset_t ratesParamSet;
|
|
||||||
#endif
|
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct cmd_ds_802_11_associate_rsp {
|
struct cmd_ds_802_11_associate_response {
|
||||||
struct ieeetypes_assocrsp assocRsp;
|
struct cmd_header hdr;
|
||||||
|
|
||||||
|
__le16 capability;
|
||||||
|
__le16 statuscode;
|
||||||
|
__le16 aid;
|
||||||
|
u8 iebuf[512];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct cmd_ds_802_11_set_wep {
|
struct cmd_ds_802_11_set_wep {
|
||||||
@ -535,9 +538,11 @@ struct cmd_ds_802_11_ad_hoc_start {
|
|||||||
u8 bsstype;
|
u8 bsstype;
|
||||||
__le16 beaconperiod;
|
__le16 beaconperiod;
|
||||||
u8 dtimperiod; /* Reserved on v9 and later */
|
u8 dtimperiod; /* Reserved on v9 and later */
|
||||||
union IEEEtypes_ssparamset ssparamset;
|
struct ieee_ie_ibss_param_set ibss;
|
||||||
union ieeetypes_phyparamset phyparamset;
|
u8 reserved1[4];
|
||||||
__le16 probedelay;
|
struct ieee_ie_ds_param_set ds;
|
||||||
|
u8 reserved2[4];
|
||||||
|
__le16 probedelay; /* Reserved on v9 and later */
|
||||||
__le16 capability;
|
__le16 capability;
|
||||||
u8 rates[MAX_RATES];
|
u8 rates[MAX_RATES];
|
||||||
u8 tlv_memory_size_pad[100];
|
u8 tlv_memory_size_pad[100];
|
||||||
@ -558,8 +563,10 @@ struct adhoc_bssdesc {
|
|||||||
u8 dtimperiod;
|
u8 dtimperiod;
|
||||||
__le64 timestamp;
|
__le64 timestamp;
|
||||||
__le64 localtime;
|
__le64 localtime;
|
||||||
union ieeetypes_phyparamset phyparamset;
|
struct ieee_ie_ds_param_set ds;
|
||||||
union IEEEtypes_ssparamset ssparamset;
|
u8 reserved1[4];
|
||||||
|
struct ieee_ie_ibss_param_set ibss;
|
||||||
|
u8 reserved2[4];
|
||||||
__le16 capability;
|
__le16 capability;
|
||||||
u8 rates[MAX_RATES];
|
u8 rates[MAX_RATES];
|
||||||
|
|
||||||
@ -765,8 +772,6 @@ struct cmd_ds_command {
|
|||||||
/* command Body */
|
/* command Body */
|
||||||
union {
|
union {
|
||||||
struct cmd_ds_802_11_ps_mode psmode;
|
struct cmd_ds_802_11_ps_mode psmode;
|
||||||
struct cmd_ds_802_11_associate associate;
|
|
||||||
struct cmd_ds_802_11_authenticate auth;
|
|
||||||
struct cmd_ds_802_11_get_stat gstat;
|
struct cmd_ds_802_11_get_stat gstat;
|
||||||
struct cmd_ds_802_3_get_stat gstat_8023;
|
struct cmd_ds_802_3_get_stat gstat_8023;
|
||||||
struct cmd_ds_802_11_rf_antenna rant;
|
struct cmd_ds_802_11_rf_antenna rant;
|
||||||
|
@ -39,8 +39,24 @@
|
|||||||
#include "decl.h"
|
#include "decl.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "dev.h"
|
#include "dev.h"
|
||||||
|
#include "cmd.h"
|
||||||
#include "if_sdio.h"
|
#include "if_sdio.h"
|
||||||
|
|
||||||
|
/* The if_sdio_remove() callback function is called when
|
||||||
|
* user removes this module from kernel space or ejects
|
||||||
|
* the card from the slot. The driver handles these 2 cases
|
||||||
|
* differently for SD8688 combo chip.
|
||||||
|
* If the user is removing the module, the FUNC_SHUTDOWN
|
||||||
|
* command for SD8688 is sent to the firmware.
|
||||||
|
* If the card is removed, there is no need to send this command.
|
||||||
|
*
|
||||||
|
* The variable 'user_rmmod' is used to distinguish these two
|
||||||
|
* scenarios. This flag is initialized as FALSE in case the card
|
||||||
|
* is removed, and will be set to TRUE for module removal when
|
||||||
|
* module_exit function is called.
|
||||||
|
*/
|
||||||
|
static u8 user_rmmod;
|
||||||
|
|
||||||
static char *lbs_helper_name = NULL;
|
static char *lbs_helper_name = NULL;
|
||||||
module_param_named(helper_name, lbs_helper_name, charp, 0644);
|
module_param_named(helper_name, lbs_helper_name, charp, 0644);
|
||||||
|
|
||||||
@ -61,7 +77,6 @@ struct if_sdio_model {
|
|||||||
int model;
|
int model;
|
||||||
const char *helper;
|
const char *helper;
|
||||||
const char *firmware;
|
const char *firmware;
|
||||||
struct if_sdio_card *card;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct if_sdio_model if_sdio_models[] = {
|
static struct if_sdio_model if_sdio_models[] = {
|
||||||
@ -70,21 +85,18 @@ static struct if_sdio_model if_sdio_models[] = {
|
|||||||
.model = IF_SDIO_MODEL_8385,
|
.model = IF_SDIO_MODEL_8385,
|
||||||
.helper = "sd8385_helper.bin",
|
.helper = "sd8385_helper.bin",
|
||||||
.firmware = "sd8385.bin",
|
.firmware = "sd8385.bin",
|
||||||
.card = NULL,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
/* 8686 */
|
/* 8686 */
|
||||||
.model = IF_SDIO_MODEL_8686,
|
.model = IF_SDIO_MODEL_8686,
|
||||||
.helper = "sd8686_helper.bin",
|
.helper = "sd8686_helper.bin",
|
||||||
.firmware = "sd8686.bin",
|
.firmware = "sd8686.bin",
|
||||||
.card = NULL,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
/* 8688 */
|
/* 8688 */
|
||||||
.model = IF_SDIO_MODEL_8688,
|
.model = IF_SDIO_MODEL_8688,
|
||||||
.helper = "sd8688_helper.bin",
|
.helper = "sd8688_helper.bin",
|
||||||
.firmware = "sd8688.bin",
|
.firmware = "sd8688.bin",
|
||||||
.card = NULL,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -927,8 +939,6 @@ static int if_sdio_probe(struct sdio_func *func,
|
|||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
if_sdio_models[i].card = card;
|
|
||||||
|
|
||||||
card->helper = if_sdio_models[i].helper;
|
card->helper = if_sdio_models[i].helper;
|
||||||
card->firmware = if_sdio_models[i].firmware;
|
card->firmware = if_sdio_models[i].firmware;
|
||||||
|
|
||||||
@ -1014,8 +1024,16 @@ static int if_sdio_probe(struct sdio_func *func,
|
|||||||
/*
|
/*
|
||||||
* FUNC_INIT is required for SD8688 WLAN/BT multiple functions
|
* FUNC_INIT is required for SD8688 WLAN/BT multiple functions
|
||||||
*/
|
*/
|
||||||
priv->fn_init_required =
|
if (card->model == IF_SDIO_MODEL_8688) {
|
||||||
(card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
|
struct cmd_header cmd;
|
||||||
|
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
|
||||||
|
lbs_deb_sdio("send function INIT command\n");
|
||||||
|
if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
|
||||||
|
lbs_cmd_copyback, (unsigned long) &cmd))
|
||||||
|
lbs_pr_alert("CMD_FUNC_INIT cmd failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
ret = lbs_start_card(priv);
|
ret = lbs_start_card(priv);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -1057,30 +1075,39 @@ static void if_sdio_remove(struct sdio_func *func)
|
|||||||
{
|
{
|
||||||
struct if_sdio_card *card;
|
struct if_sdio_card *card;
|
||||||
struct if_sdio_packet *packet;
|
struct if_sdio_packet *packet;
|
||||||
int ret;
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_SDIO);
|
lbs_deb_enter(LBS_DEB_SDIO);
|
||||||
|
|
||||||
card = sdio_get_drvdata(func);
|
card = sdio_get_drvdata(func);
|
||||||
|
|
||||||
lbs_stop_card(card->priv);
|
if (user_rmmod && (card->model == IF_SDIO_MODEL_8688)) {
|
||||||
|
/*
|
||||||
|
* FUNC_SHUTDOWN is required for SD8688 WLAN/BT
|
||||||
|
* multiple functions
|
||||||
|
*/
|
||||||
|
struct cmd_header cmd;
|
||||||
|
|
||||||
|
memset(&cmd, 0, sizeof(cmd));
|
||||||
|
|
||||||
|
lbs_deb_sdio("send function SHUTDOWN command\n");
|
||||||
|
if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
|
||||||
|
&cmd, sizeof(cmd), lbs_cmd_copyback,
|
||||||
|
(unsigned long) &cmd))
|
||||||
|
lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
card->priv->surpriseremoved = 1;
|
card->priv->surpriseremoved = 1;
|
||||||
|
|
||||||
lbs_deb_sdio("call remove card\n");
|
lbs_deb_sdio("call remove card\n");
|
||||||
|
lbs_stop_card(card->priv);
|
||||||
lbs_remove_card(card->priv);
|
lbs_remove_card(card->priv);
|
||||||
|
|
||||||
flush_workqueue(card->workqueue);
|
flush_workqueue(card->workqueue);
|
||||||
destroy_workqueue(card->workqueue);
|
destroy_workqueue(card->workqueue);
|
||||||
|
|
||||||
sdio_claim_host(func);
|
sdio_claim_host(func);
|
||||||
|
|
||||||
/* Disable interrupts */
|
|
||||||
sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret);
|
|
||||||
|
|
||||||
sdio_release_irq(func);
|
sdio_release_irq(func);
|
||||||
sdio_disable_func(func);
|
sdio_disable_func(func);
|
||||||
|
|
||||||
sdio_release_host(func);
|
sdio_release_host(func);
|
||||||
|
|
||||||
while (card->packets) {
|
while (card->packets) {
|
||||||
@ -1116,6 +1143,9 @@ static int __init if_sdio_init_module(void)
|
|||||||
|
|
||||||
ret = sdio_register_driver(&if_sdio_driver);
|
ret = sdio_register_driver(&if_sdio_driver);
|
||||||
|
|
||||||
|
/* Clear the flag in case user removes the card. */
|
||||||
|
user_rmmod = 0;
|
||||||
|
|
||||||
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -1123,22 +1153,10 @@ static int __init if_sdio_init_module(void)
|
|||||||
|
|
||||||
static void __exit if_sdio_exit_module(void)
|
static void __exit if_sdio_exit_module(void)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
struct if_sdio_card *card;
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_SDIO);
|
lbs_deb_enter(LBS_DEB_SDIO);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) {
|
/* Set the flag as user is removing this module. */
|
||||||
card = if_sdio_models[i].card;
|
user_rmmod = 1;
|
||||||
|
|
||||||
/*
|
|
||||||
* FUNC_SHUTDOWN is required for SD8688 WLAN/BT
|
|
||||||
* multiple functions
|
|
||||||
*/
|
|
||||||
if (card && card->priv)
|
|
||||||
card->priv->fn_shutdown_required =
|
|
||||||
(card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sdio_unregister_driver(&if_sdio_driver);
|
sdio_unregister_driver(&if_sdio_driver);
|
||||||
|
|
||||||
|
@ -119,9 +119,6 @@ static struct chip_ident chip_id_to_device_name[] = {
|
|||||||
* First we have to put a SPU register name on the bus. Then we can
|
* First we have to put a SPU register name on the bus. Then we can
|
||||||
* either read from or write to that register.
|
* either read from or write to that register.
|
||||||
*
|
*
|
||||||
* For 16-bit transactions, byte order on the bus is big-endian.
|
|
||||||
* We don't have to worry about that here, though.
|
|
||||||
* The translation takes place in the SPI routines.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void spu_transaction_init(struct if_spi_card *card)
|
static void spu_transaction_init(struct if_spi_card *card)
|
||||||
@ -147,7 +144,7 @@ static void spu_transaction_finish(struct if_spi_card *card)
|
|||||||
static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
|
static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u16 reg_out = reg | IF_SPI_WRITE_OPERATION_MASK;
|
u16 reg_out = cpu_to_le16(reg | IF_SPI_WRITE_OPERATION_MASK);
|
||||||
|
|
||||||
/* You must give an even number of bytes to the SPU, even if it
|
/* You must give an even number of bytes to the SPU, even if it
|
||||||
* doesn't care about the last one. */
|
* doesn't care about the last one. */
|
||||||
@ -169,16 +166,10 @@ out:
|
|||||||
|
|
||||||
static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val)
|
static inline int spu_write_u16(struct if_spi_card *card, u16 reg, u16 val)
|
||||||
{
|
{
|
||||||
return spu_write(card, reg, (u8 *)&val, sizeof(u16));
|
u16 buff;
|
||||||
}
|
|
||||||
|
|
||||||
static inline int spu_write_u32(struct if_spi_card *card, u16 reg, u32 val)
|
buff = cpu_to_le16(val);
|
||||||
{
|
return spu_write(card, reg, (u8 *)&buff, sizeof(u16));
|
||||||
/* The lower 16 bits are written first. */
|
|
||||||
u16 out[2];
|
|
||||||
out[0] = val & 0xffff;
|
|
||||||
out[1] = (val & 0xffff0000) >> 16;
|
|
||||||
return spu_write(card, reg, (u8 *)&out, sizeof(u32));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int spu_reg_is_port_reg(u16 reg)
|
static inline int spu_reg_is_port_reg(u16 reg)
|
||||||
@ -198,7 +189,7 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len)
|
|||||||
unsigned int i, delay;
|
unsigned int i, delay;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
u16 zero = 0;
|
u16 zero = 0;
|
||||||
u16 reg_out = reg | IF_SPI_READ_OPERATION_MASK;
|
u16 reg_out = cpu_to_le16(reg | IF_SPI_READ_OPERATION_MASK);
|
||||||
|
|
||||||
/* You must take an even number of bytes from the SPU, even if you
|
/* You must take an even number of bytes from the SPU, even if you
|
||||||
* don't care about the last one. */
|
* don't care about the last one. */
|
||||||
@ -236,18 +227,25 @@ out:
|
|||||||
/* Read 16 bits from an SPI register */
|
/* Read 16 bits from an SPI register */
|
||||||
static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val)
|
static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val)
|
||||||
{
|
{
|
||||||
return spu_read(card, reg, (u8 *)val, sizeof(u16));
|
u16 buf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
|
||||||
|
if (ret == 0)
|
||||||
|
*val = le16_to_cpup(&buf);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read 32 bits from an SPI register.
|
/* Read 32 bits from an SPI register.
|
||||||
* The low 16 bits are read first. */
|
* The low 16 bits are read first. */
|
||||||
static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
|
static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
|
||||||
{
|
{
|
||||||
u16 buf[2];
|
u32 buf;
|
||||||
int err;
|
int err;
|
||||||
err = spu_read(card, reg, (u8 *)buf, sizeof(u32));
|
|
||||||
|
err = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
|
||||||
if (!err)
|
if (!err)
|
||||||
*val = buf[0] | (buf[1] << 16);
|
*val = le32_to_cpup(&buf);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1002,17 +1002,9 @@ static int lbs_setup_firmware(struct lbs_private *priv)
|
|||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
s16 curlevel = 0, minlevel = 0, maxlevel = 0;
|
s16 curlevel = 0, minlevel = 0, maxlevel = 0;
|
||||||
struct cmd_header cmd;
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_FW);
|
lbs_deb_enter(LBS_DEB_FW);
|
||||||
|
|
||||||
if (priv->fn_init_required) {
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
|
||||||
if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
|
|
||||||
lbs_cmd_copyback, (unsigned long) &cmd))
|
|
||||||
lbs_pr_alert("CMD_FUNC_INIT command failed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read MAC address from firmware */
|
/* Read MAC address from firmware */
|
||||||
memset(priv->current_addr, 0xff, ETH_ALEN);
|
memset(priv->current_addr, 0xff, ETH_ALEN);
|
||||||
ret = lbs_update_hw_spec(priv);
|
ret = lbs_update_hw_spec(priv);
|
||||||
@ -1200,9 +1192,6 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
|
|||||||
priv->mesh_open = 0;
|
priv->mesh_open = 0;
|
||||||
priv->infra_open = 0;
|
priv->infra_open = 0;
|
||||||
|
|
||||||
priv->fn_init_required = 0;
|
|
||||||
priv->fn_shutdown_required = 0;
|
|
||||||
|
|
||||||
/* Setup the OS Interface to our functions */
|
/* Setup the OS Interface to our functions */
|
||||||
dev->netdev_ops = &lbs_netdev_ops;
|
dev->netdev_ops = &lbs_netdev_ops;
|
||||||
dev->watchdog_timeo = 5 * HZ;
|
dev->watchdog_timeo = 5 * HZ;
|
||||||
@ -1384,20 +1373,11 @@ void lbs_stop_card(struct lbs_private *priv)
|
|||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
struct cmd_ctrl_node *cmdnode;
|
struct cmd_ctrl_node *cmdnode;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct cmd_header cmd;
|
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_MAIN);
|
lbs_deb_enter(LBS_DEB_MAIN);
|
||||||
|
|
||||||
if (!priv)
|
if (!priv)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (priv->fn_shutdown_required) {
|
|
||||||
memset(&cmd, 0, sizeof(cmd));
|
|
||||||
if (__lbs_cmd(priv, CMD_FUNC_SHUTDOWN, &cmd, sizeof(cmd),
|
|
||||||
lbs_cmd_copyback, (unsigned long) &cmd))
|
|
||||||
lbs_pr_alert("CMD_FUNC_SHUTDOWN command failed\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
dev = priv->dev;
|
dev = priv->dev;
|
||||||
|
|
||||||
netif_stop_queue(dev);
|
netif_stop_queue(dev);
|
||||||
|
@ -27,12 +27,12 @@
|
|||||||
+ 40) /* 40 for WPAIE */
|
+ 40) /* 40 for WPAIE */
|
||||||
|
|
||||||
//! Memory needed to store a max sized channel List TLV for a firmware scan
|
//! Memory needed to store a max sized channel List TLV for a firmware scan
|
||||||
#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvlietypesheader) \
|
#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \
|
||||||
+ (MRVDRV_MAX_CHANNELS_PER_SCAN \
|
+ (MRVDRV_MAX_CHANNELS_PER_SCAN \
|
||||||
* sizeof(struct chanscanparamset)))
|
* sizeof(struct chanscanparamset)))
|
||||||
|
|
||||||
//! Memory needed to store a max number/size SSID TLV for a firmware scan
|
//! Memory needed to store a max number/size SSID TLV for a firmware scan
|
||||||
#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset))
|
#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set))
|
||||||
|
|
||||||
//! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max
|
//! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max
|
||||||
#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \
|
#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \
|
||||||
@ -211,7 +211,7 @@ static int lbs_scan_create_channel_list(struct lbs_private *priv,
|
|||||||
*/
|
*/
|
||||||
static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv)
|
static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv)
|
||||||
{
|
{
|
||||||
struct mrvlietypes_ssidparamset *ssid_tlv = (void *)tlv;
|
struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;
|
||||||
|
|
||||||
ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
|
ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
|
||||||
ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len);
|
ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len);
|
||||||
@ -249,7 +249,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,
|
|||||||
int chan_count)
|
int chan_count)
|
||||||
{
|
{
|
||||||
size_t size = sizeof(struct chanscanparamset) *chan_count;
|
size_t size = sizeof(struct chanscanparamset) *chan_count;
|
||||||
struct mrvlietypes_chanlistparamset *chan_tlv = (void *)tlv;
|
struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv;
|
||||||
|
|
||||||
chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
|
chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
|
||||||
memcpy(chan_tlv->chanscanparam, chan_list, size);
|
memcpy(chan_tlv->chanscanparam, chan_list, size);
|
||||||
@ -270,7 +270,7 @@ static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,
|
|||||||
static int lbs_scan_add_rates_tlv(uint8_t *tlv)
|
static int lbs_scan_add_rates_tlv(uint8_t *tlv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct mrvlietypes_ratesparamset *rate_tlv = (void *)tlv;
|
struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
|
||||||
|
|
||||||
rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
|
rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
|
||||||
tlv += sizeof(rate_tlv->header);
|
tlv += sizeof(rate_tlv->header);
|
||||||
@ -513,12 +513,12 @@ void lbs_scan_worker(struct work_struct *work)
|
|||||||
static int lbs_process_bss(struct bss_descriptor *bss,
|
static int lbs_process_bss(struct bss_descriptor *bss,
|
||||||
uint8_t **pbeaconinfo, int *bytesleft)
|
uint8_t **pbeaconinfo, int *bytesleft)
|
||||||
{
|
{
|
||||||
struct ieeetypes_fhparamset *pFH;
|
struct ieee_ie_fh_param_set *fh;
|
||||||
struct ieeetypes_dsparamset *pDS;
|
struct ieee_ie_ds_param_set *ds;
|
||||||
struct ieeetypes_cfparamset *pCF;
|
struct ieee_ie_cf_param_set *cf;
|
||||||
struct ieeetypes_ibssparamset *pibss;
|
struct ieee_ie_ibss_param_set *ibss;
|
||||||
DECLARE_SSID_BUF(ssid);
|
DECLARE_SSID_BUF(ssid);
|
||||||
struct ieeetypes_countryinfoset *pcountryinfo;
|
struct ieee_ie_country_info_set *pcountryinfo;
|
||||||
uint8_t *pos, *end, *p;
|
uint8_t *pos, *end, *p;
|
||||||
uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
|
uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
|
||||||
uint16_t beaconsize = 0;
|
uint16_t beaconsize = 0;
|
||||||
@ -616,50 +616,49 @@ static int lbs_process_bss(struct bss_descriptor *bss,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WLAN_EID_FH_PARAMS:
|
case WLAN_EID_FH_PARAMS:
|
||||||
pFH = (struct ieeetypes_fhparamset *) pos;
|
fh = (struct ieee_ie_fh_param_set *) pos;
|
||||||
memmove(&bss->phyparamset.fhparamset, pFH,
|
memcpy(&bss->phy.fh, fh, sizeof(*fh));
|
||||||
sizeof(struct ieeetypes_fhparamset));
|
|
||||||
lbs_deb_scan("got FH IE\n");
|
lbs_deb_scan("got FH IE\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WLAN_EID_DS_PARAMS:
|
case WLAN_EID_DS_PARAMS:
|
||||||
pDS = (struct ieeetypes_dsparamset *) pos;
|
ds = (struct ieee_ie_ds_param_set *) pos;
|
||||||
bss->channel = pDS->currentchan;
|
bss->channel = ds->channel;
|
||||||
memcpy(&bss->phyparamset.dsparamset, pDS,
|
memcpy(&bss->phy.ds, ds, sizeof(*ds));
|
||||||
sizeof(struct ieeetypes_dsparamset));
|
|
||||||
lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
|
lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WLAN_EID_CF_PARAMS:
|
case WLAN_EID_CF_PARAMS:
|
||||||
pCF = (struct ieeetypes_cfparamset *) pos;
|
cf = (struct ieee_ie_cf_param_set *) pos;
|
||||||
memcpy(&bss->ssparamset.cfparamset, pCF,
|
memcpy(&bss->ss.cf, cf, sizeof(*cf));
|
||||||
sizeof(struct ieeetypes_cfparamset));
|
|
||||||
lbs_deb_scan("got CF IE\n");
|
lbs_deb_scan("got CF IE\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WLAN_EID_IBSS_PARAMS:
|
case WLAN_EID_IBSS_PARAMS:
|
||||||
pibss = (struct ieeetypes_ibssparamset *) pos;
|
ibss = (struct ieee_ie_ibss_param_set *) pos;
|
||||||
bss->atimwindow = le16_to_cpu(pibss->atimwindow);
|
bss->atimwindow = ibss->atimwindow;
|
||||||
memmove(&bss->ssparamset.ibssparamset, pibss,
|
memcpy(&bss->ss.ibss, ibss, sizeof(*ibss));
|
||||||
sizeof(struct ieeetypes_ibssparamset));
|
|
||||||
lbs_deb_scan("got IBSS IE\n");
|
lbs_deb_scan("got IBSS IE\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WLAN_EID_COUNTRY:
|
case WLAN_EID_COUNTRY:
|
||||||
pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
|
pcountryinfo = (struct ieee_ie_country_info_set *) pos;
|
||||||
lbs_deb_scan("got COUNTRY IE\n");
|
lbs_deb_scan("got COUNTRY IE\n");
|
||||||
if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
|
if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode)
|
||||||
|| pcountryinfo->len > 254) {
|
|| pcountryinfo->header.len > 254) {
|
||||||
lbs_deb_scan("process_bss: 11D- Err CountryInfo len %d, min %zd, max 254\n",
|
lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n",
|
||||||
pcountryinfo->len, sizeof(pcountryinfo->countrycode));
|
__func__,
|
||||||
|
pcountryinfo->header.len,
|
||||||
|
sizeof(pcountryinfo->countrycode));
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&bss->countryinfo, pcountryinfo, pcountryinfo->len + 2);
|
memcpy(&bss->countryinfo, pcountryinfo,
|
||||||
|
pcountryinfo->header.len + 2);
|
||||||
lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
|
lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
|
||||||
(uint8_t *) pcountryinfo,
|
(uint8_t *) pcountryinfo,
|
||||||
(int) (pcountryinfo->len + 2));
|
(int) (pcountryinfo->header.len + 2));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WLAN_EID_EXT_SUPP_RATES:
|
case WLAN_EID_EXT_SUPP_RATES:
|
||||||
@ -1130,7 +1129,7 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,
|
|||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytesleft = le16_to_cpu(scanresp->bssdescriptsize);
|
bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize);
|
||||||
lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
|
lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
|
||||||
|
|
||||||
scanrespsize = le16_to_cpu(resp->size);
|
scanrespsize = le16_to_cpu(resp->size);
|
||||||
|
@ -8,9 +8,14 @@
|
|||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
#include <linux/wireless.h>
|
#include <linux/wireless.h>
|
||||||
|
|
||||||
struct ieeetypes_cfparamset {
|
struct ieee_ie_header {
|
||||||
u8 elementid;
|
u8 id;
|
||||||
u8 len;
|
u8 len;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct ieee_ie_cf_param_set {
|
||||||
|
struct ieee_ie_header header;
|
||||||
|
|
||||||
u8 cfpcnt;
|
u8 cfpcnt;
|
||||||
u8 cfpperiod;
|
u8 cfpperiod;
|
||||||
__le16 cfpmaxduration;
|
__le16 cfpmaxduration;
|
||||||
@ -18,42 +23,35 @@ struct ieeetypes_cfparamset {
|
|||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
struct ieeetypes_ibssparamset {
|
struct ieee_ie_ibss_param_set {
|
||||||
u8 elementid;
|
struct ieee_ie_header header;
|
||||||
u8 len;
|
|
||||||
__le16 atimwindow;
|
__le16 atimwindow;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
union IEEEtypes_ssparamset {
|
union ieee_ss_param_set {
|
||||||
struct ieeetypes_cfparamset cfparamset;
|
struct ieee_ie_cf_param_set cf;
|
||||||
struct ieeetypes_ibssparamset ibssparamset;
|
struct ieee_ie_ibss_param_set ibss;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct ieeetypes_fhparamset {
|
struct ieee_ie_fh_param_set {
|
||||||
u8 elementid;
|
struct ieee_ie_header header;
|
||||||
u8 len;
|
|
||||||
__le16 dwelltime;
|
__le16 dwelltime;
|
||||||
u8 hopset;
|
u8 hopset;
|
||||||
u8 hoppattern;
|
u8 hoppattern;
|
||||||
u8 hopindex;
|
u8 hopindex;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct ieeetypes_dsparamset {
|
struct ieee_ie_ds_param_set {
|
||||||
u8 elementid;
|
struct ieee_ie_header header;
|
||||||
u8 len;
|
|
||||||
u8 currentchan;
|
u8 channel;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
union ieeetypes_phyparamset {
|
union ieee_phy_param_set {
|
||||||
struct ieeetypes_fhparamset fhparamset;
|
struct ieee_ie_fh_param_set fh;
|
||||||
struct ieeetypes_dsparamset dsparamset;
|
struct ieee_ie_ds_param_set ds;
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct ieeetypes_assocrsp {
|
|
||||||
__le16 capability;
|
|
||||||
__le16 statuscode;
|
|
||||||
__le16 aid;
|
|
||||||
u8 iebuffer[1];
|
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/** TLV type ID definition */
|
/** TLV type ID definition */
|
||||||
@ -94,32 +92,33 @@ struct ieeetypes_assocrsp {
|
|||||||
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
|
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
|
||||||
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
|
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
|
||||||
#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
|
#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
|
||||||
|
#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
|
||||||
#define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37)
|
#define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37)
|
||||||
#define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291)
|
#define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291)
|
||||||
|
|
||||||
/** TLV related data structures*/
|
/** TLV related data structures*/
|
||||||
struct mrvlietypesheader {
|
struct mrvl_ie_header {
|
||||||
__le16 type;
|
__le16 type;
|
||||||
__le16 len;
|
__le16 len;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_data {
|
struct mrvl_ie_data {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
u8 Data[1];
|
u8 Data[1];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_ratesparamset {
|
struct mrvl_ie_rates_param_set {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
u8 rates[1];
|
u8 rates[1];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_ssidparamset {
|
struct mrvl_ie_ssid_param_set {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
u8 ssid[1];
|
u8 ssid[1];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_wildcardssidparamset {
|
struct mrvl_ie_wildcard_ssid_param_set {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
u8 MaxSsidlength;
|
u8 MaxSsidlength;
|
||||||
u8 ssid[1];
|
u8 ssid[1];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
@ -144,91 +143,72 @@ struct chanscanparamset {
|
|||||||
__le16 maxscantime;
|
__le16 maxscantime;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_chanlistparamset {
|
struct mrvl_ie_chanlist_param_set {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
struct chanscanparamset chanscanparam[1];
|
struct chanscanparamset chanscanparam[1];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct cfparamset {
|
struct mrvl_ie_cf_param_set {
|
||||||
|
struct mrvl_ie_header header;
|
||||||
u8 cfpcnt;
|
u8 cfpcnt;
|
||||||
u8 cfpperiod;
|
u8 cfpperiod;
|
||||||
__le16 cfpmaxduration;
|
__le16 cfpmaxduration;
|
||||||
__le16 cfpdurationremaining;
|
__le16 cfpdurationremaining;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct ibssparamset {
|
struct mrvl_ie_ds_param_set {
|
||||||
__le16 atimwindow;
|
struct mrvl_ie_header header;
|
||||||
|
u8 channel;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_ssparamset {
|
struct mrvl_ie_rsn_param_set {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
union {
|
|
||||||
struct cfparamset cfparamset[1];
|
|
||||||
struct ibssparamset ibssparamset[1];
|
|
||||||
} cf_ibss;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct fhparamset {
|
|
||||||
__le16 dwelltime;
|
|
||||||
u8 hopset;
|
|
||||||
u8 hoppattern;
|
|
||||||
u8 hopindex;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct dsparamset {
|
|
||||||
u8 currentchan;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct mrvlietypes_phyparamset {
|
|
||||||
struct mrvlietypesheader header;
|
|
||||||
union {
|
|
||||||
struct fhparamset fhparamset[1];
|
|
||||||
struct dsparamset dsparamset[1];
|
|
||||||
} fh_ds;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct mrvlietypes_rsnparamset {
|
|
||||||
struct mrvlietypesheader header;
|
|
||||||
u8 rsnie[1];
|
u8 rsnie[1];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_tsftimestamp {
|
struct mrvl_ie_tsf_timestamp {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
__le64 tsftable[1];
|
__le64 tsftable[1];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
/* v9 and later firmware only */
|
||||||
|
struct mrvl_ie_auth_type {
|
||||||
|
struct mrvl_ie_header header;
|
||||||
|
__le16 auth;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/** Local Power capability */
|
/** Local Power capability */
|
||||||
struct mrvlietypes_powercapability {
|
struct mrvl_ie_power_capability {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
s8 minpower;
|
s8 minpower;
|
||||||
s8 maxpower;
|
s8 maxpower;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
|
/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
|
||||||
struct mrvlietypes_thresholds {
|
struct mrvl_ie_thresholds {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
u8 value;
|
u8 value;
|
||||||
u8 freq;
|
u8 freq;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_beaconsmissed {
|
struct mrvl_ie_beacons_missed {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
u8 beaconmissed;
|
u8 beaconmissed;
|
||||||
u8 reserved;
|
u8 reserved;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_numprobes {
|
struct mrvl_ie_num_probes {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
__le16 numprobes;
|
__le16 numprobes;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_bcastprobe {
|
struct mrvl_ie_bcast_probe {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
__le16 bcastprobe;
|
__le16 bcastprobe;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_numssidprobe {
|
struct mrvl_ie_num_ssid_probe {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
__le16 numssidprobe;
|
__le16 numssidprobe;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
@ -237,8 +217,8 @@ struct led_pin {
|
|||||||
u8 pin;
|
u8 pin;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct mrvlietypes_ledgpio {
|
struct mrvl_ie_ledgpio {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
struct led_pin ledpin[1];
|
struct led_pin ledpin[1];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
@ -250,8 +230,8 @@ struct led_bhv {
|
|||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
|
||||||
struct mrvlietypes_ledbhv {
|
struct mrvl_ie_ledbhv {
|
||||||
struct mrvlietypesheader header;
|
struct mrvl_ie_header header;
|
||||||
struct led_bhv ledbhv[1];
|
struct led_bhv ledbhv[1];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
@ -280,7 +280,6 @@ struct mac80211_hwsim_data {
|
|||||||
struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
|
struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
|
||||||
|
|
||||||
struct ieee80211_channel *channel;
|
struct ieee80211_channel *channel;
|
||||||
int radio_enabled;
|
|
||||||
unsigned long beacon_int; /* in jiffies unit */
|
unsigned long beacon_int; /* in jiffies unit */
|
||||||
unsigned int rx_filter;
|
unsigned int rx_filter;
|
||||||
int started;
|
int started;
|
||||||
@ -418,8 +417,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
|
|||||||
if (data == data2)
|
if (data == data2)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!data2->started || !data2->radio_enabled ||
|
if (!data2->started || !hwsim_ps_rx_ok(data2, skb) ||
|
||||||
!hwsim_ps_rx_ok(data2, skb) ||
|
|
||||||
data->channel->center_freq != data2->channel->center_freq ||
|
data->channel->center_freq != data2->channel->center_freq ||
|
||||||
!(data->group & data2->group))
|
!(data->group & data2->group))
|
||||||
continue;
|
continue;
|
||||||
@ -441,7 +439,6 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
|
|||||||
|
|
||||||
static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct mac80211_hwsim_data *data = hw->priv;
|
|
||||||
bool ack;
|
bool ack;
|
||||||
struct ieee80211_tx_info *txi;
|
struct ieee80211_tx_info *txi;
|
||||||
|
|
||||||
@ -453,13 +450,6 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
|
|||||||
return NETDEV_TX_OK;
|
return NETDEV_TX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data->radio_enabled) {
|
|
||||||
printk(KERN_DEBUG "%s: dropped TX frame since radio "
|
|
||||||
"disabled\n", wiphy_name(hw->wiphy));
|
|
||||||
dev_kfree_skb(skb);
|
|
||||||
return NETDEV_TX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ack = mac80211_hwsim_tx_frame(hw, skb);
|
ack = mac80211_hwsim_tx_frame(hw, skb);
|
||||||
|
|
||||||
txi = IEEE80211_SKB_CB(skb);
|
txi = IEEE80211_SKB_CB(skb);
|
||||||
@ -546,7 +536,7 @@ static void mac80211_hwsim_beacon(unsigned long arg)
|
|||||||
struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
|
struct ieee80211_hw *hw = (struct ieee80211_hw *) arg;
|
||||||
struct mac80211_hwsim_data *data = hw->priv;
|
struct mac80211_hwsim_data *data = hw->priv;
|
||||||
|
|
||||||
if (!data->started || !data->radio_enabled)
|
if (!data->started)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ieee80211_iterate_active_interfaces_atomic(
|
ieee80211_iterate_active_interfaces_atomic(
|
||||||
@ -562,15 +552,14 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
|
|||||||
struct mac80211_hwsim_data *data = hw->priv;
|
struct mac80211_hwsim_data *data = hw->priv;
|
||||||
struct ieee80211_conf *conf = &hw->conf;
|
struct ieee80211_conf *conf = &hw->conf;
|
||||||
|
|
||||||
printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d idle=%d ps=%d)\n",
|
printk(KERN_DEBUG "%s:%s (freq=%d idle=%d ps=%d)\n",
|
||||||
wiphy_name(hw->wiphy), __func__,
|
wiphy_name(hw->wiphy), __func__,
|
||||||
conf->channel->center_freq, conf->radio_enabled,
|
conf->channel->center_freq,
|
||||||
!!(conf->flags & IEEE80211_CONF_IDLE),
|
!!(conf->flags & IEEE80211_CONF_IDLE),
|
||||||
!!(conf->flags & IEEE80211_CONF_PS));
|
!!(conf->flags & IEEE80211_CONF_PS));
|
||||||
|
|
||||||
data->channel = conf->channel;
|
data->channel = conf->channel;
|
||||||
data->radio_enabled = conf->radio_enabled;
|
if (!data->started || !data->beacon_int)
|
||||||
if (!data->started || !data->radio_enabled || !data->beacon_int)
|
|
||||||
del_timer(&data->beacon_timer);
|
del_timer(&data->beacon_timer);
|
||||||
else
|
else
|
||||||
mod_timer(&data->beacon_timer, jiffies + data->beacon_int);
|
mod_timer(&data->beacon_timer, jiffies + data->beacon_int);
|
||||||
@ -787,8 +776,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
|
|||||||
pspoll->aid = cpu_to_le16(0xc000 | vp->aid);
|
pspoll->aid = cpu_to_le16(0xc000 | vp->aid);
|
||||||
memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
|
memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
|
||||||
memcpy(pspoll->ta, mac, ETH_ALEN);
|
memcpy(pspoll->ta, mac, ETH_ALEN);
|
||||||
if (data->radio_enabled &&
|
if (!mac80211_hwsim_tx_frame(data->hw, skb))
|
||||||
!mac80211_hwsim_tx_frame(data->hw, skb))
|
|
||||||
printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__);
|
printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__);
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
}
|
}
|
||||||
@ -819,8 +807,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
|
|||||||
memcpy(hdr->addr1, vp->bssid, ETH_ALEN);
|
memcpy(hdr->addr1, vp->bssid, ETH_ALEN);
|
||||||
memcpy(hdr->addr2, mac, ETH_ALEN);
|
memcpy(hdr->addr2, mac, ETH_ALEN);
|
||||||
memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
|
memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
|
||||||
if (data->radio_enabled &&
|
if (!mac80211_hwsim_tx_frame(data->hw, skb))
|
||||||
!mac80211_hwsim_tx_frame(data->hw, skb))
|
|
||||||
printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
|
printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
}
|
}
|
||||||
|
@ -84,8 +84,8 @@ MODULE_DEVICE_TABLE(usb, p54u_table);
|
|||||||
static const struct {
|
static const struct {
|
||||||
u32 intf;
|
u32 intf;
|
||||||
enum p54u_hw_type type;
|
enum p54u_hw_type type;
|
||||||
char fw[FIRMWARE_NAME_MAX];
|
const char *fw;
|
||||||
char fw_legacy[FIRMWARE_NAME_MAX];
|
const char *fw_legacy;
|
||||||
char hw[20];
|
char hw[20];
|
||||||
} p54u_fwlist[__NUM_P54U_HWTYPES] = {
|
} p54u_fwlist[__NUM_P54U_HWTYPES] = {
|
||||||
{
|
{
|
||||||
|
@ -520,7 +520,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
|
|||||||
if (state == STATE_SLEEP) {
|
if (state == STATE_SLEEP) {
|
||||||
rt2x00pci_register_read(rt2x00dev, CSR20, ®);
|
rt2x00pci_register_read(rt2x00dev, CSR20, ®);
|
||||||
rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN,
|
rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN,
|
||||||
(libconf->conf->beacon_int - 20) * 16);
|
(rt2x00dev->beacon_int - 20) * 16);
|
||||||
rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP,
|
rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP,
|
||||||
libconf->conf->listen_interval - 1);
|
libconf->conf->listen_interval - 1);
|
||||||
|
|
||||||
|
@ -569,7 +569,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
|
|||||||
if (state == STATE_SLEEP) {
|
if (state == STATE_SLEEP) {
|
||||||
rt2x00pci_register_read(rt2x00dev, CSR20, ®);
|
rt2x00pci_register_read(rt2x00dev, CSR20, ®);
|
||||||
rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN,
|
rt2x00_set_field32(®, CSR20_DELAY_AFTER_TBCN,
|
||||||
(libconf->conf->beacon_int - 20) * 16);
|
(rt2x00dev->beacon_int - 20) * 16);
|
||||||
rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP,
|
rt2x00_set_field32(®, CSR20_TBCN_BEFORE_WAKEUP,
|
||||||
libconf->conf->listen_interval - 1);
|
libconf->conf->listen_interval - 1);
|
||||||
|
|
||||||
|
@ -647,7 +647,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev,
|
|||||||
if (state == STATE_SLEEP) {
|
if (state == STATE_SLEEP) {
|
||||||
rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®);
|
rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®);
|
||||||
rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON,
|
rt2x00_set_field16(®, MAC_CSR18_DELAY_AFTER_BEACON,
|
||||||
libconf->conf->beacon_int - 20);
|
rt2x00dev->beacon_int - 20);
|
||||||
rt2x00_set_field16(®, MAC_CSR18_BEACONS_BEFORE_WAKEUP,
|
rt2x00_set_field16(®, MAC_CSR18_BEACONS_BEFORE_WAKEUP,
|
||||||
libconf->conf->listen_interval - 1);
|
libconf->conf->listen_interval - 1);
|
||||||
|
|
||||||
|
@ -2927,12 +2927,17 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||||||
{ USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Edimax */
|
/* Edimax */
|
||||||
{ USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
/* Encore */
|
||||||
|
{ USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* EnGenius */
|
/* EnGenius */
|
||||||
{ USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0X1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
@ -2951,6 +2956,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||||||
{ USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
/* I-O DATA */
|
||||||
|
{ USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* LevelOne */
|
/* LevelOne */
|
||||||
{ USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
@ -2970,6 +2977,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||||||
/* Pegatron */
|
/* Pegatron */
|
||||||
{ USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Philips */
|
/* Philips */
|
||||||
{ USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Planex */
|
/* Planex */
|
||||||
@ -2981,6 +2989,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||||||
/* Quanta */
|
/* Quanta */
|
||||||
{ USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Ralink */
|
/* Ralink */
|
||||||
|
{ USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
@ -3005,6 +3014,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||||||
{ USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* SMC */
|
/* SMC */
|
||||||
{ USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
@ -3029,6 +3039,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
|
|||||||
/* Zinwell */
|
/* Zinwell */
|
||||||
{ USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
{ USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
/* Zyxel */
|
/* Zyxel */
|
||||||
{ USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
{ USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) },
|
{ USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) },
|
||||||
|
@ -801,6 +801,11 @@ struct rt2x00_dev {
|
|||||||
*/
|
*/
|
||||||
u8 calibration[2];
|
u8 calibration[2];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Beacon interval.
|
||||||
|
*/
|
||||||
|
u16 beacon_int;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Low level statistics which will have
|
* Low level statistics which will have
|
||||||
* to be kept up to date while device is running.
|
* to be kept up to date while device is running.
|
||||||
|
@ -108,6 +108,9 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
|
|||||||
erp.basic_rates = bss_conf->basic_rates;
|
erp.basic_rates = bss_conf->basic_rates;
|
||||||
erp.beacon_int = bss_conf->beacon_int;
|
erp.beacon_int = bss_conf->beacon_int;
|
||||||
|
|
||||||
|
/* Update global beacon interval time, this is needed for PS support */
|
||||||
|
rt2x00dev->beacon_int = bss_conf->beacon_int;
|
||||||
|
|
||||||
rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
|
rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -956,7 +956,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev,
|
|||||||
if (state == STATE_SLEEP) {
|
if (state == STATE_SLEEP) {
|
||||||
rt2x00pci_register_read(rt2x00dev, MAC_CSR11, ®);
|
rt2x00pci_register_read(rt2x00dev, MAC_CSR11, ®);
|
||||||
rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN,
|
rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN,
|
||||||
libconf->conf->beacon_int - 10);
|
rt2x00dev->beacon_int - 10);
|
||||||
rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP,
|
rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP,
|
||||||
libconf->conf->listen_interval - 1);
|
libconf->conf->listen_interval - 1);
|
||||||
rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5);
|
rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5);
|
||||||
|
@ -852,7 +852,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev,
|
|||||||
if (state == STATE_SLEEP) {
|
if (state == STATE_SLEEP) {
|
||||||
rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®);
|
rt2x00usb_register_read(rt2x00dev, MAC_CSR11, ®);
|
||||||
rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN,
|
rt2x00_set_field32(®, MAC_CSR11_DELAY_AFTER_TBCN,
|
||||||
libconf->conf->beacon_int - 10);
|
rt2x00dev->beacon_int - 10);
|
||||||
rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP,
|
rt2x00_set_field32(®, MAC_CSR11_TBCN_BEFORE_WAKEUP,
|
||||||
libconf->conf->listen_interval - 1);
|
libconf->conf->listen_interval - 1);
|
||||||
rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5);
|
rt2x00_set_field32(®, MAC_CSR11_WAKEUP_LATENCY, 5);
|
||||||
|
@ -21,7 +21,7 @@ config ACER_WMI
|
|||||||
depends on NEW_LEDS
|
depends on NEW_LEDS
|
||||||
depends on BACKLIGHT_CLASS_DEVICE
|
depends on BACKLIGHT_CLASS_DEVICE
|
||||||
depends on SERIO_I8042
|
depends on SERIO_I8042
|
||||||
depends on RFKILL
|
depends on RFKILL || RFKILL = n
|
||||||
select ACPI_WMI
|
select ACPI_WMI
|
||||||
---help---
|
---help---
|
||||||
This is a driver for newer Acer (and Wistron) laptops. It adds
|
This is a driver for newer Acer (and Wistron) laptops. It adds
|
||||||
@ -60,7 +60,7 @@ config DELL_LAPTOP
|
|||||||
depends on DCDBAS
|
depends on DCDBAS
|
||||||
depends on EXPERIMENTAL
|
depends on EXPERIMENTAL
|
||||||
depends on BACKLIGHT_CLASS_DEVICE
|
depends on BACKLIGHT_CLASS_DEVICE
|
||||||
depends on RFKILL
|
depends on RFKILL || RFKILL = n
|
||||||
depends on POWER_SUPPLY
|
depends on POWER_SUPPLY
|
||||||
default n
|
default n
|
||||||
---help---
|
---help---
|
||||||
@ -117,7 +117,7 @@ config HP_WMI
|
|||||||
tristate "HP WMI extras"
|
tristate "HP WMI extras"
|
||||||
depends on ACPI_WMI
|
depends on ACPI_WMI
|
||||||
depends on INPUT
|
depends on INPUT
|
||||||
depends on RFKILL
|
depends on RFKILL || RFKILL = n
|
||||||
help
|
help
|
||||||
Say Y here if you want to support WMI-based hotkeys on HP laptops and
|
Say Y here if you want to support WMI-based hotkeys on HP laptops and
|
||||||
to read data from WMI such as docking or ambient light sensor state.
|
to read data from WMI such as docking or ambient light sensor state.
|
||||||
@ -196,14 +196,13 @@ config THINKPAD_ACPI
|
|||||||
tristate "ThinkPad ACPI Laptop Extras"
|
tristate "ThinkPad ACPI Laptop Extras"
|
||||||
depends on ACPI
|
depends on ACPI
|
||||||
depends on INPUT
|
depends on INPUT
|
||||||
|
depends on RFKILL || RFKILL = n
|
||||||
select BACKLIGHT_LCD_SUPPORT
|
select BACKLIGHT_LCD_SUPPORT
|
||||||
select BACKLIGHT_CLASS_DEVICE
|
select BACKLIGHT_CLASS_DEVICE
|
||||||
select HWMON
|
select HWMON
|
||||||
select NVRAM
|
select NVRAM
|
||||||
select NEW_LEDS
|
select NEW_LEDS
|
||||||
select LEDS_CLASS
|
select LEDS_CLASS
|
||||||
select NET
|
|
||||||
select RFKILL
|
|
||||||
---help---
|
---help---
|
||||||
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
|
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
|
||||||
support for Fn-Fx key combinations, Bluetooth control, video
|
support for Fn-Fx key combinations, Bluetooth control, video
|
||||||
@ -338,9 +337,9 @@ config EEEPC_LAPTOP
|
|||||||
depends on ACPI
|
depends on ACPI
|
||||||
depends on INPUT
|
depends on INPUT
|
||||||
depends on EXPERIMENTAL
|
depends on EXPERIMENTAL
|
||||||
|
depends on RFKILL || RFKILL = n
|
||||||
select BACKLIGHT_CLASS_DEVICE
|
select BACKLIGHT_CLASS_DEVICE
|
||||||
select HWMON
|
select HWMON
|
||||||
select RFKILL
|
|
||||||
---help---
|
---help---
|
||||||
This driver supports the Fn-Fx keys on Eee PC laptops.
|
This driver supports the Fn-Fx keys on Eee PC laptops.
|
||||||
It also adds the ability to switch camera/wlan on/off.
|
It also adds the ability to switch camera/wlan on/off.
|
||||||
@ -405,9 +404,8 @@ config ACPI_TOSHIBA
|
|||||||
tristate "Toshiba Laptop Extras"
|
tristate "Toshiba Laptop Extras"
|
||||||
depends on ACPI
|
depends on ACPI
|
||||||
depends on INPUT
|
depends on INPUT
|
||||||
|
depends on RFKILL || RFKILL = n
|
||||||
select INPUT_POLLDEV
|
select INPUT_POLLDEV
|
||||||
select NET
|
|
||||||
select RFKILL
|
|
||||||
select BACKLIGHT_CLASS_DEVICE
|
select BACKLIGHT_CLASS_DEVICE
|
||||||
---help---
|
---help---
|
||||||
This driver adds support for access to certain system settings
|
This driver adds support for access to certain system settings
|
||||||
|
@ -958,58 +958,50 @@ static void acer_rfkill_update(struct work_struct *ignored)
|
|||||||
|
|
||||||
status = get_u32(&state, ACER_CAP_WIRELESS);
|
status = get_u32(&state, ACER_CAP_WIRELESS);
|
||||||
if (ACPI_SUCCESS(status))
|
if (ACPI_SUCCESS(status))
|
||||||
rfkill_force_state(wireless_rfkill, state ?
|
rfkill_set_sw_state(wireless_rfkill, !!state);
|
||||||
RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
|
|
||||||
|
|
||||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||||
status = get_u32(&state, ACER_CAP_BLUETOOTH);
|
status = get_u32(&state, ACER_CAP_BLUETOOTH);
|
||||||
if (ACPI_SUCCESS(status))
|
if (ACPI_SUCCESS(status))
|
||||||
rfkill_force_state(bluetooth_rfkill, state ?
|
rfkill_set_sw_state(bluetooth_rfkill, !!state);
|
||||||
RFKILL_STATE_UNBLOCKED :
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
|
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int acer_rfkill_set(void *data, enum rfkill_state state)
|
static int acer_rfkill_set(void *data, bool blocked)
|
||||||
{
|
{
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
u32 *cap = data;
|
u32 cap = (unsigned long)data;
|
||||||
status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
|
status = set_u32(!!blocked, cap);
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rfkill * acer_rfkill_register(struct device *dev,
|
static const struct rfkill_ops acer_rfkill_ops = {
|
||||||
enum rfkill_type type, char *name, u32 cap)
|
.set_block = acer_rfkill_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct rfkill *acer_rfkill_register(struct device *dev,
|
||||||
|
enum rfkill_type type,
|
||||||
|
char *name, u32 cap)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
u32 state;
|
u32 state;
|
||||||
u32 *data;
|
|
||||||
struct rfkill *rfkill_dev;
|
struct rfkill *rfkill_dev;
|
||||||
|
|
||||||
rfkill_dev = rfkill_allocate(dev, type);
|
rfkill_dev = rfkill_alloc(name, dev, type,
|
||||||
|
&acer_rfkill_ops,
|
||||||
|
(void *)(unsigned long)cap);
|
||||||
if (!rfkill_dev)
|
if (!rfkill_dev)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
rfkill_dev->name = name;
|
|
||||||
get_u32(&state, cap);
|
get_u32(&state, cap);
|
||||||
rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
|
rfkill_set_sw_state(rfkill_dev, !state);
|
||||||
RFKILL_STATE_SOFT_BLOCKED;
|
|
||||||
data = kzalloc(sizeof(u32), GFP_KERNEL);
|
|
||||||
if (!data) {
|
|
||||||
rfkill_free(rfkill_dev);
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
|
||||||
*data = cap;
|
|
||||||
rfkill_dev->data = data;
|
|
||||||
rfkill_dev->toggle_radio = acer_rfkill_set;
|
|
||||||
|
|
||||||
err = rfkill_register(rfkill_dev);
|
err = rfkill_register(rfkill_dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
kfree(rfkill_dev->data);
|
rfkill_destroy(rfkill_dev);
|
||||||
rfkill_free(rfkill_dev);
|
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
return rfkill_dev;
|
return rfkill_dev;
|
||||||
@ -1027,8 +1019,8 @@ static int acer_rfkill_init(struct device *dev)
|
|||||||
RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
|
RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
|
||||||
ACER_CAP_BLUETOOTH);
|
ACER_CAP_BLUETOOTH);
|
||||||
if (IS_ERR(bluetooth_rfkill)) {
|
if (IS_ERR(bluetooth_rfkill)) {
|
||||||
kfree(wireless_rfkill->data);
|
|
||||||
rfkill_unregister(wireless_rfkill);
|
rfkill_unregister(wireless_rfkill);
|
||||||
|
rfkill_destroy(wireless_rfkill);
|
||||||
return PTR_ERR(bluetooth_rfkill);
|
return PTR_ERR(bluetooth_rfkill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1041,11 +1033,13 @@ static int acer_rfkill_init(struct device *dev)
|
|||||||
static void acer_rfkill_exit(void)
|
static void acer_rfkill_exit(void)
|
||||||
{
|
{
|
||||||
cancel_delayed_work_sync(&acer_rfkill_work);
|
cancel_delayed_work_sync(&acer_rfkill_work);
|
||||||
kfree(wireless_rfkill->data);
|
|
||||||
rfkill_unregister(wireless_rfkill);
|
rfkill_unregister(wireless_rfkill);
|
||||||
|
rfkill_destroy(wireless_rfkill);
|
||||||
|
|
||||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||||
kfree(bluetooth_rfkill->data);
|
|
||||||
rfkill_unregister(bluetooth_rfkill);
|
rfkill_unregister(bluetooth_rfkill);
|
||||||
|
rfkill_destroy(bluetooth_rfkill);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
|
|||||||
result[3]: NVRAM format version number
|
result[3]: NVRAM format version number
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int dell_rfkill_set(int radio, enum rfkill_state state)
|
static int dell_rfkill_set(void *data, bool blocked)
|
||||||
{
|
{
|
||||||
struct calling_interface_buffer buffer;
|
struct calling_interface_buffer buffer;
|
||||||
int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1;
|
int disable = blocked ? 0 : 1;
|
||||||
|
unsigned long radio = (unsigned long)data;
|
||||||
|
|
||||||
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
||||||
buffer.input[0] = (1 | (radio<<8) | (disable << 16));
|
buffer.input[0] = (1 | (radio<<8) | (disable << 16));
|
||||||
@ -186,56 +187,24 @@ static int dell_rfkill_set(int radio, enum rfkill_state state)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dell_wifi_set(void *data, enum rfkill_state state)
|
static void dell_rfkill_query(struct rfkill *rfkill, void *data)
|
||||||
{
|
|
||||||
return dell_rfkill_set(1, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dell_bluetooth_set(void *data, enum rfkill_state state)
|
|
||||||
{
|
|
||||||
return dell_rfkill_set(2, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dell_wwan_set(void *data, enum rfkill_state state)
|
|
||||||
{
|
|
||||||
return dell_rfkill_set(3, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dell_rfkill_get(int bit, enum rfkill_state *state)
|
|
||||||
{
|
{
|
||||||
struct calling_interface_buffer buffer;
|
struct calling_interface_buffer buffer;
|
||||||
int status;
|
int status;
|
||||||
int new_state = RFKILL_STATE_HARD_BLOCKED;
|
int bit = (unsigned long)data + 16;
|
||||||
|
|
||||||
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
||||||
dell_send_request(&buffer, 17, 11);
|
dell_send_request(&buffer, 17, 11);
|
||||||
status = buffer.output[1];
|
status = buffer.output[1];
|
||||||
|
|
||||||
if (status & (1<<16))
|
if (status & BIT(bit))
|
||||||
new_state = RFKILL_STATE_SOFT_BLOCKED;
|
rfkill_set_hw_state(rfkill, !!(status & BIT(16)));
|
||||||
|
|
||||||
if (status & (1<<bit))
|
|
||||||
*state = new_state;
|
|
||||||
else
|
|
||||||
*state = RFKILL_STATE_UNBLOCKED;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dell_wifi_get(void *data, enum rfkill_state *state)
|
static const struct rfkill_ops dell_rfkill_ops = {
|
||||||
{
|
.set_block = dell_rfkill_set,
|
||||||
return dell_rfkill_get(17, state);
|
.query = dell_rfkill_query,
|
||||||
}
|
};
|
||||||
|
|
||||||
static int dell_bluetooth_get(void *data, enum rfkill_state *state)
|
|
||||||
{
|
|
||||||
return dell_rfkill_get(18, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dell_wwan_get(void *data, enum rfkill_state *state)
|
|
||||||
{
|
|
||||||
return dell_rfkill_get(19, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dell_setup_rfkill(void)
|
static int dell_setup_rfkill(void)
|
||||||
{
|
{
|
||||||
@ -248,36 +217,37 @@ static int dell_setup_rfkill(void)
|
|||||||
status = buffer.output[1];
|
status = buffer.output[1];
|
||||||
|
|
||||||
if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
|
if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
|
||||||
wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN);
|
wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN,
|
||||||
if (!wifi_rfkill)
|
&dell_rfkill_ops, (void *) 1);
|
||||||
|
if (!wifi_rfkill) {
|
||||||
|
ret = -ENOMEM;
|
||||||
goto err_wifi;
|
goto err_wifi;
|
||||||
wifi_rfkill->name = "dell-wifi";
|
}
|
||||||
wifi_rfkill->toggle_radio = dell_wifi_set;
|
|
||||||
wifi_rfkill->get_state = dell_wifi_get;
|
|
||||||
ret = rfkill_register(wifi_rfkill);
|
ret = rfkill_register(wifi_rfkill);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_wifi;
|
goto err_wifi;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
|
if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
|
||||||
bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH);
|
bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL,
|
||||||
if (!bluetooth_rfkill)
|
RFKILL_TYPE_BLUETOOTH,
|
||||||
|
&dell_rfkill_ops, (void *) 2);
|
||||||
|
if (!bluetooth_rfkill) {
|
||||||
|
ret = -ENOMEM;
|
||||||
goto err_bluetooth;
|
goto err_bluetooth;
|
||||||
bluetooth_rfkill->name = "dell-bluetooth";
|
}
|
||||||
bluetooth_rfkill->toggle_radio = dell_bluetooth_set;
|
|
||||||
bluetooth_rfkill->get_state = dell_bluetooth_get;
|
|
||||||
ret = rfkill_register(bluetooth_rfkill);
|
ret = rfkill_register(bluetooth_rfkill);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_bluetooth;
|
goto err_bluetooth;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
|
if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
|
||||||
wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN);
|
wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN,
|
||||||
if (!wwan_rfkill)
|
&dell_rfkill_ops, (void *) 3);
|
||||||
|
if (!wwan_rfkill) {
|
||||||
|
ret = -ENOMEM;
|
||||||
goto err_wwan;
|
goto err_wwan;
|
||||||
wwan_rfkill->name = "dell-wwan";
|
}
|
||||||
wwan_rfkill->toggle_radio = dell_wwan_set;
|
|
||||||
wwan_rfkill->get_state = dell_wwan_get;
|
|
||||||
ret = rfkill_register(wwan_rfkill);
|
ret = rfkill_register(wwan_rfkill);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_wwan;
|
goto err_wwan;
|
||||||
@ -285,22 +255,15 @@ static int dell_setup_rfkill(void)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err_wwan:
|
err_wwan:
|
||||||
if (wwan_rfkill)
|
rfkill_destroy(wwan_rfkill);
|
||||||
rfkill_free(wwan_rfkill);
|
|
||||||
if (bluetooth_rfkill) {
|
|
||||||
rfkill_unregister(bluetooth_rfkill);
|
|
||||||
bluetooth_rfkill = NULL;
|
|
||||||
}
|
|
||||||
err_bluetooth:
|
|
||||||
if (bluetooth_rfkill)
|
if (bluetooth_rfkill)
|
||||||
rfkill_free(bluetooth_rfkill);
|
rfkill_unregister(bluetooth_rfkill);
|
||||||
if (wifi_rfkill) {
|
err_bluetooth:
|
||||||
rfkill_unregister(wifi_rfkill);
|
rfkill_destroy(bluetooth_rfkill);
|
||||||
wifi_rfkill = NULL;
|
|
||||||
}
|
|
||||||
err_wifi:
|
|
||||||
if (wifi_rfkill)
|
if (wifi_rfkill)
|
||||||
rfkill_free(wifi_rfkill);
|
rfkill_unregister(wifi_rfkill);
|
||||||
|
err_wifi:
|
||||||
|
rfkill_destroy(wifi_rfkill);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd)
|
|||||||
* Rfkill helpers
|
* Rfkill helpers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
|
static bool eeepc_wlan_rfkill_blocked(void)
|
||||||
{
|
|
||||||
if (state == RFKILL_STATE_SOFT_BLOCKED)
|
|
||||||
return set_acpi(CM_ASL_WLAN, 0);
|
|
||||||
else
|
|
||||||
return set_acpi(CM_ASL_WLAN, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
|
|
||||||
{
|
{
|
||||||
if (get_acpi(CM_ASL_WLAN) == 1)
|
if (get_acpi(CM_ASL_WLAN) == 1)
|
||||||
*state = RFKILL_STATE_UNBLOCKED;
|
return false;
|
||||||
else
|
return true;
|
||||||
*state = RFKILL_STATE_SOFT_BLOCKED;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state)
|
static int eeepc_rfkill_set(void *data, bool blocked)
|
||||||
{
|
{
|
||||||
if (state == RFKILL_STATE_SOFT_BLOCKED)
|
unsigned long asl = (unsigned long)data;
|
||||||
return set_acpi(CM_ASL_BLUETOOTH, 0);
|
return set_acpi(asl, !blocked);
|
||||||
else
|
|
||||||
return set_acpi(CM_ASL_BLUETOOTH, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
|
static const struct rfkill_ops eeepc_rfkill_ops = {
|
||||||
{
|
.set_block = eeepc_rfkill_set,
|
||||||
if (get_acpi(CM_ASL_BLUETOOTH) == 1)
|
};
|
||||||
*state = RFKILL_STATE_UNBLOCKED;
|
|
||||||
else
|
|
||||||
*state = RFKILL_STATE_SOFT_BLOCKED;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sys helpers
|
* Sys helpers
|
||||||
@ -531,9 +514,9 @@ static int notify_brn(void)
|
|||||||
|
|
||||||
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
||||||
{
|
{
|
||||||
enum rfkill_state state;
|
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
struct pci_bus *bus = pci_find_bus(0, 1);
|
struct pci_bus *bus = pci_find_bus(0, 1);
|
||||||
|
bool blocked;
|
||||||
|
|
||||||
if (event != ACPI_NOTIFY_BUS_CHECK)
|
if (event != ACPI_NOTIFY_BUS_CHECK)
|
||||||
return;
|
return;
|
||||||
@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state);
|
blocked = eeepc_wlan_rfkill_blocked();
|
||||||
|
if (!blocked) {
|
||||||
if (state == RFKILL_STATE_UNBLOCKED) {
|
|
||||||
dev = pci_get_slot(bus, 0);
|
dev = pci_get_slot(bus, 0);
|
||||||
if (dev) {
|
if (dev) {
|
||||||
/* Device already present */
|
/* Device already present */
|
||||||
@ -566,7 +548,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rfkill_force_state(ehotk->eeepc_wlan_rfkill, state);
|
rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
|
static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
|
||||||
@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
|||||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
|
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
|
||||||
|
|
||||||
if (get_acpi(CM_ASL_WLAN) != -1) {
|
if (get_acpi(CM_ASL_WLAN) != -1) {
|
||||||
ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
|
ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
|
||||||
RFKILL_TYPE_WLAN);
|
&device->dev,
|
||||||
|
RFKILL_TYPE_WLAN,
|
||||||
|
&eeepc_rfkill_ops,
|
||||||
|
(void *)CM_ASL_WLAN);
|
||||||
|
|
||||||
if (!ehotk->eeepc_wlan_rfkill)
|
if (!ehotk->eeepc_wlan_rfkill)
|
||||||
goto wlan_fail;
|
goto wlan_fail;
|
||||||
|
|
||||||
ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
|
rfkill_set_global_sw_state(RFKILL_TYPE_WLAN,
|
||||||
ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
|
get_acpi(CM_ASL_WLAN) != 1);
|
||||||
ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
|
|
||||||
if (get_acpi(CM_ASL_WLAN) == 1) {
|
|
||||||
ehotk->eeepc_wlan_rfkill->state =
|
|
||||||
RFKILL_STATE_UNBLOCKED;
|
|
||||||
rfkill_set_default(RFKILL_TYPE_WLAN,
|
|
||||||
RFKILL_STATE_UNBLOCKED);
|
|
||||||
} else {
|
|
||||||
ehotk->eeepc_wlan_rfkill->state =
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED;
|
|
||||||
rfkill_set_default(RFKILL_TYPE_WLAN,
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED);
|
|
||||||
}
|
|
||||||
result = rfkill_register(ehotk->eeepc_wlan_rfkill);
|
result = rfkill_register(ehotk->eeepc_wlan_rfkill);
|
||||||
if (result)
|
if (result)
|
||||||
goto wlan_fail;
|
goto wlan_fail;
|
||||||
@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
|||||||
|
|
||||||
if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
|
if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
|
||||||
ehotk->eeepc_bluetooth_rfkill =
|
ehotk->eeepc_bluetooth_rfkill =
|
||||||
rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
|
rfkill_alloc("eeepc-bluetooth",
|
||||||
|
&device->dev,
|
||||||
|
RFKILL_TYPE_BLUETOOTH,
|
||||||
|
&eeepc_rfkill_ops,
|
||||||
|
(void *)CM_ASL_BLUETOOTH);
|
||||||
|
|
||||||
if (!ehotk->eeepc_bluetooth_rfkill)
|
if (!ehotk->eeepc_bluetooth_rfkill)
|
||||||
goto bluetooth_fail;
|
goto bluetooth_fail;
|
||||||
|
|
||||||
ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
|
rfkill_set_global_sw_state(RFKILL_TYPE_BLUETOOTH,
|
||||||
ehotk->eeepc_bluetooth_rfkill->toggle_radio =
|
get_acpi(CM_ASL_BLUETOOTH) != 1);
|
||||||
eeepc_bluetooth_rfkill_set;
|
|
||||||
ehotk->eeepc_bluetooth_rfkill->get_state =
|
|
||||||
eeepc_bluetooth_rfkill_state;
|
|
||||||
if (get_acpi(CM_ASL_BLUETOOTH) == 1) {
|
|
||||||
ehotk->eeepc_bluetooth_rfkill->state =
|
|
||||||
RFKILL_STATE_UNBLOCKED;
|
|
||||||
rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
|
|
||||||
RFKILL_STATE_UNBLOCKED);
|
|
||||||
} else {
|
|
||||||
ehotk->eeepc_bluetooth_rfkill->state =
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED;
|
|
||||||
rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED);
|
|
||||||
}
|
|
||||||
|
|
||||||
result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
|
result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
|
||||||
if (result)
|
if (result)
|
||||||
goto bluetooth_fail;
|
goto bluetooth_fail;
|
||||||
@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bluetooth_fail:
|
bluetooth_fail:
|
||||||
if (ehotk->eeepc_bluetooth_rfkill)
|
rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
|
||||||
rfkill_free(ehotk->eeepc_bluetooth_rfkill);
|
|
||||||
rfkill_unregister(ehotk->eeepc_wlan_rfkill);
|
rfkill_unregister(ehotk->eeepc_wlan_rfkill);
|
||||||
ehotk->eeepc_wlan_rfkill = NULL;
|
|
||||||
wlan_fail:
|
wlan_fail:
|
||||||
if (ehotk->eeepc_wlan_rfkill)
|
rfkill_destroy(ehotk->eeepc_wlan_rfkill);
|
||||||
rfkill_free(ehotk->eeepc_wlan_rfkill);
|
|
||||||
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
|
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
|
||||||
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
|
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
|
||||||
ehotk_fail:
|
ehotk_fail:
|
||||||
|
@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void)
|
|||||||
return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0);
|
return hp_wmi_perform_query(HPWMI_DOCK_QUERY, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hp_wmi_wifi_set(void *data, enum rfkill_state state)
|
static int hp_wmi_set_block(void *data, bool blocked)
|
||||||
{
|
{
|
||||||
if (state)
|
unsigned long b = (unsigned long) data;
|
||||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101);
|
int query = BIT(b + 8) | ((!!blocked) << b);
|
||||||
else
|
|
||||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100);
|
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state)
|
static const struct rfkill_ops hp_wmi_rfkill_ops = {
|
||||||
{
|
.set_block = hp_wmi_set_block,
|
||||||
if (state)
|
};
|
||||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202);
|
|
||||||
else
|
|
||||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hp_wmi_wwan_set(void *data, enum rfkill_state state)
|
static bool hp_wmi_wifi_state(void)
|
||||||
{
|
|
||||||
if (state)
|
|
||||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x404);
|
|
||||||
else
|
|
||||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x400);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hp_wmi_wifi_state(void)
|
|
||||||
{
|
{
|
||||||
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
||||||
|
|
||||||
if (wireless & 0x100)
|
if (wireless & 0x100)
|
||||||
return RFKILL_STATE_UNBLOCKED;
|
return false;
|
||||||
else
|
else
|
||||||
return RFKILL_STATE_SOFT_BLOCKED;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hp_wmi_bluetooth_state(void)
|
static bool hp_wmi_bluetooth_state(void)
|
||||||
{
|
{
|
||||||
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
||||||
|
|
||||||
if (wireless & 0x10000)
|
if (wireless & 0x10000)
|
||||||
return RFKILL_STATE_UNBLOCKED;
|
return false;
|
||||||
else
|
else
|
||||||
return RFKILL_STATE_SOFT_BLOCKED;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hp_wmi_wwan_state(void)
|
static bool hp_wmi_wwan_state(void)
|
||||||
{
|
{
|
||||||
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
||||||
|
|
||||||
if (wireless & 0x1000000)
|
if (wireless & 0x1000000)
|
||||||
return RFKILL_STATE_UNBLOCKED;
|
return false;
|
||||||
else
|
else
|
||||||
return RFKILL_STATE_SOFT_BLOCKED;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_display(struct device *dev, struct device_attribute *attr,
|
static ssize_t show_display(struct device *dev, struct device_attribute *attr,
|
||||||
@ -347,14 +335,14 @@ static void hp_wmi_notify(u32 value, void *context)
|
|||||||
}
|
}
|
||||||
} else if (eventcode == 0x5) {
|
} else if (eventcode == 0x5) {
|
||||||
if (wifi_rfkill)
|
if (wifi_rfkill)
|
||||||
rfkill_force_state(wifi_rfkill,
|
rfkill_set_sw_state(wifi_rfkill,
|
||||||
hp_wmi_wifi_state());
|
hp_wmi_wifi_state());
|
||||||
if (bluetooth_rfkill)
|
if (bluetooth_rfkill)
|
||||||
rfkill_force_state(bluetooth_rfkill,
|
rfkill_set_sw_state(bluetooth_rfkill,
|
||||||
hp_wmi_bluetooth_state());
|
hp_wmi_bluetooth_state());
|
||||||
if (wwan_rfkill)
|
if (wwan_rfkill)
|
||||||
rfkill_force_state(wwan_rfkill,
|
rfkill_set_sw_state(wwan_rfkill,
|
||||||
hp_wmi_wwan_state());
|
hp_wmi_wwan_state());
|
||||||
} else
|
} else
|
||||||
printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
|
printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
|
||||||
eventcode);
|
eventcode);
|
||||||
@ -430,31 +418,34 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
|
|||||||
goto add_sysfs_error;
|
goto add_sysfs_error;
|
||||||
|
|
||||||
if (wireless & 0x1) {
|
if (wireless & 0x1) {
|
||||||
wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
|
wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
|
||||||
wifi_rfkill->name = "hp-wifi";
|
RFKILL_TYPE_WLAN,
|
||||||
wifi_rfkill->state = hp_wmi_wifi_state();
|
&hp_wmi_rfkill_ops,
|
||||||
wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
|
(void *) 0);
|
||||||
|
rfkill_set_sw_state(wifi_rfkill, hp_wmi_wifi_state());
|
||||||
err = rfkill_register(wifi_rfkill);
|
err = rfkill_register(wifi_rfkill);
|
||||||
if (err)
|
if (err)
|
||||||
goto add_sysfs_error;
|
goto register_wifi_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wireless & 0x2) {
|
if (wireless & 0x2) {
|
||||||
bluetooth_rfkill = rfkill_allocate(&device->dev,
|
bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
|
||||||
RFKILL_TYPE_BLUETOOTH);
|
RFKILL_TYPE_BLUETOOTH,
|
||||||
bluetooth_rfkill->name = "hp-bluetooth";
|
&hp_wmi_rfkill_ops,
|
||||||
bluetooth_rfkill->state = hp_wmi_bluetooth_state();
|
(void *) 1);
|
||||||
bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
|
rfkill_set_sw_state(bluetooth_rfkill,
|
||||||
|
hp_wmi_bluetooth_state());
|
||||||
err = rfkill_register(bluetooth_rfkill);
|
err = rfkill_register(bluetooth_rfkill);
|
||||||
if (err)
|
if (err)
|
||||||
goto register_bluetooth_error;
|
goto register_bluetooth_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wireless & 0x4) {
|
if (wireless & 0x4) {
|
||||||
wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
|
wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
|
||||||
wwan_rfkill->name = "hp-wwan";
|
RFKILL_TYPE_WWAN,
|
||||||
wwan_rfkill->state = hp_wmi_wwan_state();
|
&hp_wmi_rfkill_ops,
|
||||||
wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
|
(void *) 2);
|
||||||
|
rfkill_set_sw_state(wwan_rfkill, hp_wmi_wwan_state());
|
||||||
err = rfkill_register(wwan_rfkill);
|
err = rfkill_register(wwan_rfkill);
|
||||||
if (err)
|
if (err)
|
||||||
goto register_wwan_err;
|
goto register_wwan_err;
|
||||||
@ -462,11 +453,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
register_wwan_err:
|
register_wwan_err:
|
||||||
|
rfkill_destroy(wwan_rfkill);
|
||||||
if (bluetooth_rfkill)
|
if (bluetooth_rfkill)
|
||||||
rfkill_unregister(bluetooth_rfkill);
|
rfkill_unregister(bluetooth_rfkill);
|
||||||
register_bluetooth_error:
|
register_bluetooth_error:
|
||||||
|
rfkill_destroy(bluetooth_rfkill);
|
||||||
if (wifi_rfkill)
|
if (wifi_rfkill)
|
||||||
rfkill_unregister(wifi_rfkill);
|
rfkill_unregister(wifi_rfkill);
|
||||||
|
register_wifi_error:
|
||||||
|
rfkill_destroy(wifi_rfkill);
|
||||||
add_sysfs_error:
|
add_sysfs_error:
|
||||||
cleanup_sysfs(device);
|
cleanup_sysfs(device);
|
||||||
return err;
|
return err;
|
||||||
@ -476,12 +471,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
|
|||||||
{
|
{
|
||||||
cleanup_sysfs(device);
|
cleanup_sysfs(device);
|
||||||
|
|
||||||
if (wifi_rfkill)
|
if (wifi_rfkill) {
|
||||||
rfkill_unregister(wifi_rfkill);
|
rfkill_unregister(wifi_rfkill);
|
||||||
if (bluetooth_rfkill)
|
rfkill_destroy(wifi_rfkill);
|
||||||
|
}
|
||||||
|
if (bluetooth_rfkill) {
|
||||||
rfkill_unregister(bluetooth_rfkill);
|
rfkill_unregister(bluetooth_rfkill);
|
||||||
if (wwan_rfkill)
|
rfkill_destroy(wifi_rfkill);
|
||||||
|
}
|
||||||
|
if (wwan_rfkill) {
|
||||||
rfkill_unregister(wwan_rfkill);
|
rfkill_unregister(wwan_rfkill);
|
||||||
|
rfkill_destroy(wwan_rfkill);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -128,11 +128,11 @@ enum sony_nc_rfkill {
|
|||||||
SONY_BLUETOOTH,
|
SONY_BLUETOOTH,
|
||||||
SONY_WWAN,
|
SONY_WWAN,
|
||||||
SONY_WIMAX,
|
SONY_WIMAX,
|
||||||
SONY_RFKILL_MAX,
|
N_SONY_RFKILL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX];
|
static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
|
||||||
static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900};
|
static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
|
||||||
static void sony_nc_rfkill_update(void);
|
static void sony_nc_rfkill_update(void);
|
||||||
|
|
||||||
/*********** Input Devices ***********/
|
/*********** Input Devices ***********/
|
||||||
@ -1051,147 +1051,98 @@ static void sony_nc_rfkill_cleanup(void)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < SONY_RFKILL_MAX; i++) {
|
for (i = 0; i < N_SONY_RFKILL; i++) {
|
||||||
if (sony_rfkill_devices[i])
|
if (sony_rfkill_devices[i]) {
|
||||||
rfkill_unregister(sony_rfkill_devices[i]);
|
rfkill_unregister(sony_rfkill_devices[i]);
|
||||||
|
rfkill_destroy(sony_rfkill_devices[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sony_nc_rfkill_get(void *data, enum rfkill_state *state)
|
static int sony_nc_rfkill_set(void *data, bool blocked)
|
||||||
{
|
|
||||||
int result;
|
|
||||||
int argument = sony_rfkill_address[(long) data];
|
|
||||||
|
|
||||||
sony_call_snc_handle(0x124, 0x200, &result);
|
|
||||||
if (result & 0x1) {
|
|
||||||
sony_call_snc_handle(0x124, argument, &result);
|
|
||||||
if (result & 0xf)
|
|
||||||
*state = RFKILL_STATE_UNBLOCKED;
|
|
||||||
else
|
|
||||||
*state = RFKILL_STATE_SOFT_BLOCKED;
|
|
||||||
} else {
|
|
||||||
*state = RFKILL_STATE_HARD_BLOCKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sony_nc_rfkill_set(void *data, enum rfkill_state state)
|
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
int argument = sony_rfkill_address[(long) data] + 0x100;
|
int argument = sony_rfkill_address[(long) data] + 0x100;
|
||||||
|
|
||||||
if (state == RFKILL_STATE_UNBLOCKED)
|
if (!blocked)
|
||||||
argument |= 0xff0000;
|
argument |= 0xff0000;
|
||||||
|
|
||||||
return sony_call_snc_handle(0x124, argument, &result);
|
return sony_call_snc_handle(0x124, argument, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sony_nc_setup_wifi_rfkill(struct acpi_device *device)
|
static const struct rfkill_ops sony_rfkill_ops = {
|
||||||
|
.set_block = sony_nc_rfkill_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int sony_nc_setup_rfkill(struct acpi_device *device,
|
||||||
|
enum sony_nc_rfkill nc_type)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct rfkill *sony_wifi_rfkill;
|
struct rfkill *rfk;
|
||||||
|
enum rfkill_type type;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
sony_wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
|
switch (nc_type) {
|
||||||
if (!sony_wifi_rfkill)
|
case SONY_WIFI:
|
||||||
return -1;
|
type = RFKILL_TYPE_WLAN;
|
||||||
sony_wifi_rfkill->name = "sony-wifi";
|
name = "sony-wifi";
|
||||||
sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set;
|
break;
|
||||||
sony_wifi_rfkill->get_state = sony_nc_rfkill_get;
|
case SONY_BLUETOOTH:
|
||||||
sony_wifi_rfkill->data = (void *)SONY_WIFI;
|
type = RFKILL_TYPE_BLUETOOTH;
|
||||||
err = rfkill_register(sony_wifi_rfkill);
|
name = "sony-bluetooth";
|
||||||
if (err)
|
break;
|
||||||
rfkill_free(sony_wifi_rfkill);
|
case SONY_WWAN:
|
||||||
else {
|
type = RFKILL_TYPE_WWAN;
|
||||||
sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill;
|
name = "sony-wwan";
|
||||||
sony_nc_rfkill_set(sony_wifi_rfkill->data,
|
break;
|
||||||
RFKILL_STATE_UNBLOCKED);
|
case SONY_WIMAX:
|
||||||
|
type = RFKILL_TYPE_WIMAX;
|
||||||
|
name = "sony-wimax";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sony_nc_setup_bluetooth_rfkill(struct acpi_device *device)
|
rfk = rfkill_alloc(name, &device->dev, type,
|
||||||
{
|
&sony_rfkill_ops, (void *)nc_type);
|
||||||
int err = 0;
|
if (!rfk)
|
||||||
struct rfkill *sony_bluetooth_rfkill;
|
return -ENOMEM;
|
||||||
|
|
||||||
sony_bluetooth_rfkill = rfkill_allocate(&device->dev,
|
err = rfkill_register(rfk);
|
||||||
RFKILL_TYPE_BLUETOOTH);
|
if (err) {
|
||||||
if (!sony_bluetooth_rfkill)
|
rfkill_destroy(rfk);
|
||||||
return -1;
|
return err;
|
||||||
sony_bluetooth_rfkill->name = "sony-bluetooth";
|
|
||||||
sony_bluetooth_rfkill->toggle_radio = sony_nc_rfkill_set;
|
|
||||||
sony_bluetooth_rfkill->get_state = sony_nc_rfkill_get;
|
|
||||||
sony_bluetooth_rfkill->data = (void *)SONY_BLUETOOTH;
|
|
||||||
err = rfkill_register(sony_bluetooth_rfkill);
|
|
||||||
if (err)
|
|
||||||
rfkill_free(sony_bluetooth_rfkill);
|
|
||||||
else {
|
|
||||||
sony_rfkill_devices[SONY_BLUETOOTH] = sony_bluetooth_rfkill;
|
|
||||||
sony_nc_rfkill_set(sony_bluetooth_rfkill->data,
|
|
||||||
RFKILL_STATE_UNBLOCKED);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sony_nc_setup_wwan_rfkill(struct acpi_device *device)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
struct rfkill *sony_wwan_rfkill;
|
|
||||||
|
|
||||||
sony_wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
|
|
||||||
if (!sony_wwan_rfkill)
|
|
||||||
return -1;
|
|
||||||
sony_wwan_rfkill->name = "sony-wwan";
|
|
||||||
sony_wwan_rfkill->toggle_radio = sony_nc_rfkill_set;
|
|
||||||
sony_wwan_rfkill->get_state = sony_nc_rfkill_get;
|
|
||||||
sony_wwan_rfkill->data = (void *)SONY_WWAN;
|
|
||||||
err = rfkill_register(sony_wwan_rfkill);
|
|
||||||
if (err)
|
|
||||||
rfkill_free(sony_wwan_rfkill);
|
|
||||||
else {
|
|
||||||
sony_rfkill_devices[SONY_WWAN] = sony_wwan_rfkill;
|
|
||||||
sony_nc_rfkill_set(sony_wwan_rfkill->data,
|
|
||||||
RFKILL_STATE_UNBLOCKED);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sony_nc_setup_wimax_rfkill(struct acpi_device *device)
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
struct rfkill *sony_wimax_rfkill;
|
|
||||||
|
|
||||||
sony_wimax_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WIMAX);
|
|
||||||
if (!sony_wimax_rfkill)
|
|
||||||
return -1;
|
|
||||||
sony_wimax_rfkill->name = "sony-wimax";
|
|
||||||
sony_wimax_rfkill->toggle_radio = sony_nc_rfkill_set;
|
|
||||||
sony_wimax_rfkill->get_state = sony_nc_rfkill_get;
|
|
||||||
sony_wimax_rfkill->data = (void *)SONY_WIMAX;
|
|
||||||
err = rfkill_register(sony_wimax_rfkill);
|
|
||||||
if (err)
|
|
||||||
rfkill_free(sony_wimax_rfkill);
|
|
||||||
else {
|
|
||||||
sony_rfkill_devices[SONY_WIMAX] = sony_wimax_rfkill;
|
|
||||||
sony_nc_rfkill_set(sony_wimax_rfkill->data,
|
|
||||||
RFKILL_STATE_UNBLOCKED);
|
|
||||||
}
|
}
|
||||||
|
sony_rfkill_devices[nc_type] = rfk;
|
||||||
|
sony_nc_rfkill_set((void *)nc_type, false);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sony_nc_rfkill_update()
|
static void sony_nc_rfkill_update()
|
||||||
{
|
{
|
||||||
int i;
|
enum sony_nc_rfkill i;
|
||||||
enum rfkill_state state;
|
int result;
|
||||||
|
bool hwblock;
|
||||||
|
|
||||||
for (i = 0; i < SONY_RFKILL_MAX; i++) {
|
sony_call_snc_handle(0x124, 0x200, &result);
|
||||||
if (sony_rfkill_devices[i]) {
|
hwblock = !(result & 0x1);
|
||||||
sony_rfkill_devices[i]->
|
|
||||||
get_state(sony_rfkill_devices[i]->data,
|
for (i = 0; i < N_SONY_RFKILL; i++) {
|
||||||
&state);
|
int argument = sony_rfkill_address[i];
|
||||||
rfkill_force_state(sony_rfkill_devices[i], state);
|
|
||||||
|
if (!sony_rfkill_devices[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (hwblock) {
|
||||||
|
if (rfkill_set_hw_state(sony_rfkill_devices[i], true))
|
||||||
|
sony_nc_rfkill_set(sony_rfkill_devices[i],
|
||||||
|
true);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sony_call_snc_handle(0x124, argument, &result);
|
||||||
|
rfkill_set_states(sony_rfkill_devices[i],
|
||||||
|
!(result & 0xf), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1210,13 +1161,13 @@ static int sony_nc_rfkill_setup(struct acpi_device *device)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result & 0x1)
|
if (result & 0x1)
|
||||||
sony_nc_setup_wifi_rfkill(device);
|
sony_nc_setup_rfkill(device, SONY_WIFI);
|
||||||
if (result & 0x2)
|
if (result & 0x2)
|
||||||
sony_nc_setup_bluetooth_rfkill(device);
|
sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
|
||||||
if (result & 0x1c)
|
if (result & 0x1c)
|
||||||
sony_nc_setup_wwan_rfkill(device);
|
sony_nc_setup_rfkill(device, SONY_WWAN);
|
||||||
if (result & 0x20)
|
if (result & 0x20)
|
||||||
sony_nc_setup_wimax_rfkill(device);
|
sony_nc_setup_rfkill(device, SONY_WIMAX);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -45,7 +45,6 @@
|
|||||||
#include <linux/backlight.h>
|
#include <linux/backlight.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/rfkill.h>
|
#include <linux/rfkill.h>
|
||||||
#include <linux/input-polldev.h>
|
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
@ -250,21 +249,15 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
|
|||||||
|
|
||||||
struct toshiba_acpi_dev {
|
struct toshiba_acpi_dev {
|
||||||
struct platform_device *p_dev;
|
struct platform_device *p_dev;
|
||||||
struct rfkill *rfk_dev;
|
struct rfkill *bt_rfk;
|
||||||
struct input_polled_dev *poll_dev;
|
|
||||||
|
|
||||||
const char *bt_name;
|
const char *bt_name;
|
||||||
const char *rfk_name;
|
|
||||||
|
|
||||||
bool last_rfk_state;
|
|
||||||
|
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct toshiba_acpi_dev toshiba_acpi = {
|
static struct toshiba_acpi_dev toshiba_acpi = {
|
||||||
.bt_name = "Toshiba Bluetooth",
|
.bt_name = "Toshiba Bluetooth",
|
||||||
.rfk_name = "Toshiba RFKill Switch",
|
|
||||||
.last_rfk_state = false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Bluetooth rfkill handlers */
|
/* Bluetooth rfkill handlers */
|
||||||
@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present)
|
|||||||
return hci_result;
|
return hci_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 hci_get_bt_on(bool *on)
|
|
||||||
{
|
|
||||||
u32 hci_result;
|
|
||||||
u32 value, value2;
|
|
||||||
|
|
||||||
value = 0;
|
|
||||||
value2 = 0x0001;
|
|
||||||
hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
|
|
||||||
if (hci_result == HCI_SUCCESS)
|
|
||||||
*on = (value & HCI_WIRELESS_BT_POWER) &&
|
|
||||||
(value & HCI_WIRELESS_BT_ATTACH);
|
|
||||||
|
|
||||||
return hci_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 hci_get_radio_state(bool *radio_state)
|
static u32 hci_get_radio_state(bool *radio_state)
|
||||||
{
|
{
|
||||||
u32 hci_result;
|
u32 hci_result;
|
||||||
@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state)
|
|||||||
return hci_result;
|
return hci_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
|
static int bt_rfkill_set_block(void *data, bool blocked)
|
||||||
{
|
{
|
||||||
|
struct toshiba_acpi_dev *dev = data;
|
||||||
u32 result1, result2;
|
u32 result1, result2;
|
||||||
u32 value;
|
u32 value;
|
||||||
|
int err;
|
||||||
bool radio_state;
|
bool radio_state;
|
||||||
struct toshiba_acpi_dev *dev = data;
|
|
||||||
|
|
||||||
value = (state == RFKILL_STATE_UNBLOCKED);
|
value = (blocked == false);
|
||||||
|
|
||||||
if (hci_get_radio_state(&radio_state) != HCI_SUCCESS)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
switch (state) {
|
|
||||||
case RFKILL_STATE_UNBLOCKED:
|
|
||||||
if (!radio_state)
|
|
||||||
return -EPERM;
|
|
||||||
break;
|
|
||||||
case RFKILL_STATE_SOFT_BLOCKED:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&dev->mutex);
|
mutex_lock(&dev->mutex);
|
||||||
|
if (hci_get_radio_state(&radio_state) != HCI_SUCCESS) {
|
||||||
|
err = -EBUSY;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!radio_state) {
|
||||||
|
err = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
|
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
|
||||||
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
|
hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
|
||||||
mutex_unlock(&dev->mutex);
|
|
||||||
|
|
||||||
if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
|
if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
|
||||||
return -EFAULT;
|
err = -EBUSY;
|
||||||
|
else
|
||||||
return 0;
|
err = 0;
|
||||||
|
out:
|
||||||
|
mutex_unlock(&dev->mutex);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bt_poll_rfkill(struct input_polled_dev *poll_dev)
|
static void bt_rfkill_poll(struct rfkill *rfkill, void *data)
|
||||||
{
|
{
|
||||||
bool state_changed;
|
|
||||||
bool new_rfk_state;
|
bool new_rfk_state;
|
||||||
bool value;
|
bool value;
|
||||||
u32 hci_result;
|
u32 hci_result;
|
||||||
struct toshiba_acpi_dev *dev = poll_dev->private;
|
struct toshiba_acpi_dev *dev = data;
|
||||||
|
|
||||||
|
mutex_lock(&dev->mutex);
|
||||||
|
|
||||||
hci_result = hci_get_radio_state(&value);
|
hci_result = hci_get_radio_state(&value);
|
||||||
if (hci_result != HCI_SUCCESS)
|
if (hci_result != HCI_SUCCESS) {
|
||||||
return; /* Can't do anything useful */
|
/* Can't do anything useful */
|
||||||
|
mutex_unlock(&dev->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
new_rfk_state = value;
|
new_rfk_state = value;
|
||||||
|
|
||||||
mutex_lock(&dev->mutex);
|
|
||||||
state_changed = new_rfk_state != dev->last_rfk_state;
|
|
||||||
dev->last_rfk_state = new_rfk_state;
|
|
||||||
mutex_unlock(&dev->mutex);
|
mutex_unlock(&dev->mutex);
|
||||||
|
|
||||||
if (unlikely(state_changed)) {
|
if (rfkill_set_hw_state(rfkill, !new_rfk_state))
|
||||||
rfkill_force_state(dev->rfk_dev,
|
bt_rfkill_set_block(data, true);
|
||||||
new_rfk_state ?
|
|
||||||
RFKILL_STATE_SOFT_BLOCKED :
|
|
||||||
RFKILL_STATE_HARD_BLOCKED);
|
|
||||||
input_report_switch(poll_dev->input, SW_RFKILL_ALL,
|
|
||||||
new_rfk_state);
|
|
||||||
input_sync(poll_dev->input);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct rfkill_ops toshiba_rfk_ops = {
|
||||||
|
.set_block = bt_rfkill_set_block,
|
||||||
|
.poll = bt_rfkill_poll,
|
||||||
|
};
|
||||||
|
|
||||||
static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
|
static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
|
||||||
static struct backlight_device *toshiba_backlight_device;
|
static struct backlight_device *toshiba_backlight_device;
|
||||||
static int force_fan;
|
static int force_fan;
|
||||||
@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = {
|
|||||||
|
|
||||||
static void toshiba_acpi_exit(void)
|
static void toshiba_acpi_exit(void)
|
||||||
{
|
{
|
||||||
if (toshiba_acpi.poll_dev) {
|
if (toshiba_acpi.bt_rfk) {
|
||||||
input_unregister_polled_device(toshiba_acpi.poll_dev);
|
rfkill_unregister(toshiba_acpi.bt_rfk);
|
||||||
input_free_polled_device(toshiba_acpi.poll_dev);
|
rfkill_destroy(toshiba_acpi.bt_rfk);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toshiba_acpi.rfk_dev)
|
|
||||||
rfkill_unregister(toshiba_acpi.rfk_dev);
|
|
||||||
|
|
||||||
if (toshiba_backlight_device)
|
if (toshiba_backlight_device)
|
||||||
backlight_device_unregister(toshiba_backlight_device);
|
backlight_device_unregister(toshiba_backlight_device);
|
||||||
|
|
||||||
@ -728,8 +700,6 @@ static int __init toshiba_acpi_init(void)
|
|||||||
acpi_status status = AE_OK;
|
acpi_status status = AE_OK;
|
||||||
u32 hci_result;
|
u32 hci_result;
|
||||||
bool bt_present;
|
bool bt_present;
|
||||||
bool bt_on;
|
|
||||||
bool radio_on;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (acpi_disabled)
|
if (acpi_disabled)
|
||||||
@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void)
|
|||||||
|
|
||||||
/* Register rfkill switch for Bluetooth */
|
/* Register rfkill switch for Bluetooth */
|
||||||
if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
|
if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
|
||||||
toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev,
|
toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name,
|
||||||
RFKILL_TYPE_BLUETOOTH);
|
&toshiba_acpi.p_dev->dev,
|
||||||
if (!toshiba_acpi.rfk_dev) {
|
RFKILL_TYPE_BLUETOOTH,
|
||||||
|
&toshiba_rfk_ops,
|
||||||
|
&toshiba_acpi);
|
||||||
|
if (!toshiba_acpi.bt_rfk) {
|
||||||
printk(MY_ERR "unable to allocate rfkill device\n");
|
printk(MY_ERR "unable to allocate rfkill device\n");
|
||||||
toshiba_acpi_exit();
|
toshiba_acpi_exit();
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
|
ret = rfkill_register(toshiba_acpi.bt_rfk);
|
||||||
toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio;
|
|
||||||
toshiba_acpi.rfk_dev->data = &toshiba_acpi;
|
|
||||||
|
|
||||||
if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) {
|
|
||||||
toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED;
|
|
||||||
} else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS &&
|
|
||||||
radio_on) {
|
|
||||||
toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED;
|
|
||||||
} else {
|
|
||||||
toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = rfkill_register(toshiba_acpi.rfk_dev);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(MY_ERR "unable to register rfkill device\n");
|
printk(MY_ERR "unable to register rfkill device\n");
|
||||||
toshiba_acpi_exit();
|
rfkill_destroy(toshiba_acpi.bt_rfk);
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Register input device for kill switch */
|
|
||||||
toshiba_acpi.poll_dev = input_allocate_polled_device();
|
|
||||||
if (!toshiba_acpi.poll_dev) {
|
|
||||||
printk(MY_ERR
|
|
||||||
"unable to allocate kill-switch input device\n");
|
|
||||||
toshiba_acpi_exit();
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
toshiba_acpi.poll_dev->private = &toshiba_acpi;
|
|
||||||
toshiba_acpi.poll_dev->poll = bt_poll_rfkill;
|
|
||||||
toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */
|
|
||||||
|
|
||||||
toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name;
|
|
||||||
toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST;
|
|
||||||
/* Toshiba USB ID */
|
|
||||||
toshiba_acpi.poll_dev->input->id.vendor = 0x0930;
|
|
||||||
set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit);
|
|
||||||
set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit);
|
|
||||||
input_report_switch(toshiba_acpi.poll_dev->input,
|
|
||||||
SW_RFKILL_ALL, TRUE);
|
|
||||||
input_sync(toshiba_acpi.poll_dev->input);
|
|
||||||
|
|
||||||
ret = input_register_polled_device(toshiba_acpi.poll_dev);
|
|
||||||
if (ret) {
|
|
||||||
printk(MY_ERR
|
|
||||||
"unable to register kill-switch input device\n");
|
|
||||||
toshiba_acpi_exit();
|
toshiba_acpi_exit();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -106,4 +106,6 @@
|
|||||||
#define EOWNERDEAD 130 /* Owner died */
|
#define EOWNERDEAD 130 /* Owner died */
|
||||||
#define ENOTRECOVERABLE 131 /* State not recoverable */
|
#define ENOTRECOVERABLE 131 /* State not recoverable */
|
||||||
|
|
||||||
|
#define ERFKILL 132 /* Operation not possible due to RF-kill */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -311,6 +311,7 @@ unifdef-y += ptrace.h
|
|||||||
unifdef-y += qnx4_fs.h
|
unifdef-y += qnx4_fs.h
|
||||||
unifdef-y += quota.h
|
unifdef-y += quota.h
|
||||||
unifdef-y += random.h
|
unifdef-y += random.h
|
||||||
|
unifdef-y += rfkill.h
|
||||||
unifdef-y += irqnr.h
|
unifdef-y += irqnr.h
|
||||||
unifdef-y += reboot.h
|
unifdef-y += reboot.h
|
||||||
unifdef-y += reiserfs_fs.h
|
unifdef-y += reiserfs_fs.h
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user