Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2009-06-07 04:24:21 -07:00
commit b1bc81a0ef
133 changed files with 4504 additions and 4737 deletions

View file

@ -437,3 +437,10 @@ Why: Superseded by tdfxfb. I2C/DDC support used to live in a separate
driver but this caused driver conflicts.
Who: Jean Delvare <khali@linux-fr.org>
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>

View file

@ -1,571 +1,136 @@
rfkill - RF switch subsystem support
====================================
rfkill - RF kill switch support
===============================
1 Introduction
2 Implementation details
3 Kernel driver guidelines
3.1 wireless device drivers
3.2 platform/switch drivers
3.3 input device drivers
4 Kernel API
5 Userspace support
1. Introduction
2. Implementation details
3. Kernel driver guidelines
4. Kernel API
5. Userspace support
1. Introduction:
1. Introduction
The rfkill switch subsystem exists to add a generic interface to circuitry that
can enable or disable the signal output of a wireless *transmitter* of any
type. By far, the most common use is to disable radio-frequency transmitters.
The rfkill subsystem provides a generic interface to disabling any radio
transmitter in the system. When a transmitter is blocked, it shall not
radiate any power.
Note that disabling the signal output means that the the transmitter is to be
made to not emit any energy when "blocked". rfkill is not about blocking data
transmissions, it is about blocking energy emission.
The subsystem also provides the ability to react on button presses and
disable all transmitters of a certain type (or all). This is intended for
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
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
2. Implementation details
The rfkill subsystem is composed of various components: the rfkill class, the
rfkill-input module (an input layer handler), and some specific input layer
events.
The rfkill class provides kernel drivers with an interface that allows them to
know when they should enable or disable a wireless network device transmitter.
This is enabled by the CONFIG_RFKILL Kconfig option.
The rfkill class is provided for kernel drivers to register their radio
transmitter with the kernel, provide methods for turning it on and off and,
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
changes on rfkill devices through uevents. It provides a notification chain
for interested parties in the kernel to also get notified of rfkill state
changes in other drivers. It creates several sysfs entries which can be used
by userspace. See section "Userspace support".
The rfkill class code also notifies userspace of state changes, this is
achieved via uevents. It also provides some sysfs files for userspace to
check the status of radio transmitters. See the "Userspace support" section
below.
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
listen to all rfkill key events and will change the rfkill state of the
wireless devices accordingly. With this option enabled userspace could either
do nothing or simply perform monitoring tasks.
The rfkill-input code implements a basic response to rfkill buttons -- it
implements turning on/off all devices of a certain class (or all).
The rfkill-input module also provides EPO (emergency power-off) functionality
for all wireless transmitters. This function cannot be overridden, and it is
always active. rfkill EPO is related to *_RFKILL_ALL input layer events.
When the device is hard-blocked (either by a call to rfkill_set_hw_state()
or from query_hw_block) set_block() will be invoked but drivers can well
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
referring to an electronic control circuit that enables or disables a
transmitter. We reserve it for the physical device a human manipulates
(which is an input device, by the way):
* The kernel input layer generates KEY_WWAN, KEY_WLAN etc. and
SW_RFKILL_ALL -- when the user presses a button. Drivers for radio
transmitters generally do not register to the input layer, unless the
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 kernel either directly (through a GPIO pin, ACPI GPE) or by its
effect on a rfkill line of a wireless device.
* The rfkill drivers turn off/on their transmitters as requested.
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
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).
3. Kernel driver guidelines
soft rfkill line/software rfkill line:
A rfkill line the wireless device driver can directly change the state
of. Related to rfkill_state RFKILL_STATE_SOFT_BLOCKED.
Drivers for radio transmitters normally implement only the rfkill class.
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
be overridden by the kernel driver. The hardware device or the
firmware just exports its status to the driver, but it is read-only.
Related to rfkill_state RFKILL_STATE_HARD_BLOCKED.
During suspend/hibernation, transmitters should only be left enabled when
wake-on wlan or similar functionality requires it and the device wasn't
blocked before suspend/hibernate. Note that it may be necessary to update
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
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
4. Kernel API
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
of the hardware is unknown), or read-write (where the hardware can be queried
about its current state).
The rfkill class will call the get_state hook of a device every time it needs
to know the *real* current state of the hardware. This can happen often, but
it does not do any polling, so it is not enough on hardware that is subject
to state changes outside of the rfkill subsystem.
Calling rfkill_set_hw_state() when a state change happens is required from
rfkill drivers that control devices that can be hard-blocked unless they also
assign the poll_hw_block() callback (then the rfkill core will poll the
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
rfkill status, should there be any chance of the device status changing during
the sleep.
5. Userspace support
There is no provision for a statically-allocated rfkill struct. You must
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:
The following sysfs entries exist for every rfkill device:
name: Name assigned by driver to this key (interface or driver name).
type: Name of the key type ("wlan", "bluetooth", etc).
state: Current state of the transmitter
0: RFKILL_STATE_SOFT_BLOCKED
transmitter is forced off, but one can override it
by a write to the state attribute;
transmitter is turned off by software
1: RFKILL_STATE_UNBLOCKED
transmiter is NOT forced off, and may operate if
all other conditions for such operation are met
(such as interface is up and configured, etc);
transmitter is (potentially) active
2: RFKILL_STATE_HARD_BLOCKED
transmitter is forced off by something outside of
the driver's control. One cannot set a device to
this state through writes to the state attribute;
claim: 1: Userspace handles events, 0: Kernel handles events
the driver's control.
claim: 0: Kernel handles events (currently always reads that value)
Both the "state" and "claim" entries are also writable. For the "state" entry
this means that when 1 or 0 is written, the device rfkill state (if not yet in
the requested state), will be will be toggled accordingly.
rfkill devices also issue uevents (with an action of "change"), with the
following environment variables set:
For the "claim" entry writing 1 to it means that the kernel no longer handles
key events even though RFKILL_INPUT input was enabled. When "claim" has been
set to 0, userspace should make sure that it listens for the input events or
check the sysfs "state" entry regularly to correctly perform the required tasks
when the rkfill key is pressed.
RFKILL_NAME
RFKILL_STATE
RFKILL_TYPE
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
SW_RFKILL_ALL), you will need to use an IOCTL. That information is not
available through sysfs in a generic way at this time, and it is not available
through the rfkill class AT ALL.
An alternative userspace interface exists as a misc device /dev/rfkill,
which allows userspace to obtain and set the state of rfkill devices and
sets of devices. It also notifies userspace about device addition and
removal. The API is a simple read/write API that is defined in
linux/rfkill.h.

View file

@ -4753,9 +4753,9 @@ S: Supported
F: fs/reiserfs/
RFKILL
P: Ivo van Doorn
M: IvDoorn@gmail.com
L: netdev@vger.kernel.org
P: Johannes Berg
M: johannes@sipsolutions.net
L: linux-wireless@vger.kernel.org
S: Maintained
F Documentation/rfkill.txt
F: net/rfkill/

View file

@ -35,21 +35,25 @@ static void tosa_bt_off(struct tosa_bt_data *data)
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",
state == RFKILL_STATE_UNBLOCKED ? "on" : "off");
pr_info("BT_RADIO going: %s\n", blocked ? "off" : "on");
if (state == RFKILL_STATE_UNBLOCKED) {
if (!blocked) {
pr_info("TOSA_BT: going ON\n");
tosa_bt_on(data);
} else {
pr_info("TOSA_BT: going OFF\n");
tosa_bt_off(data);
}
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)
{
int rc;
@ -70,18 +74,14 @@ static int tosa_bt_probe(struct platform_device *dev)
if (rc)
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) {
rc = -ENOMEM;
goto err_rfk_alloc;
}
rfk->name = "tosa-bt";
rfk->toggle_radio = tosa_bt_toggle_radio;
rfk->data = data;
#ifdef CONFIG_RFKILL_LEDS
rfk->led_trigger.name = "tosa-bt";
#endif
rfkill_set_led_trigger_name(rfk, "tosa-bt");
rc = rfkill_register(rfk);
if (rc)
@ -92,9 +92,7 @@ static int tosa_bt_probe(struct platform_device *dev)
return 0;
err_rfkill:
if (rfk)
rfkill_free(rfk);
rfk = NULL;
rfkill_destroy(rfk);
err_rfk_alloc:
tosa_bt_off(data);
err_pwr_dir:
@ -113,8 +111,10 @@ static int __devexit tosa_bt_remove(struct platform_device *dev)
platform_set_drvdata(dev, NULL);
if (rfk)
if (rfk) {
rfkill_unregister(rfk);
rfkill_destroy(rfk);
}
rfk = NULL;
tosa_bt_off(data);

View file

@ -31,7 +31,6 @@
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/pda_power.h>
#include <linux/rfkill.h>
#include <linux/spi/spi.h>
#include <asm/setup.h>

View file

@ -2481,10 +2481,10 @@ static int add_net_device(struct hso_device *hso_dev)
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;
int enabled = (state == RFKILL_STATE_UNBLOCKED);
int enabled = !blocked;
int rv;
mutex_lock(&hso_dev->mutex);
@ -2498,6 +2498,10 @@ static int hso_radio_toggle(void *data, enum rfkill_state state)
return rv;
}
static const struct rfkill_ops hso_rfkill_ops = {
.set_block = hso_rfkill_set_block,
};
/* Creates and sets up everything for rfkill */
static void hso_create_rfkill(struct hso_device *hso_dev,
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;
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);
if (!rfkn) {
rfkill_free(hso_net->rfkill);
hso_net->rfkill = NULL;
if (!rfkn)
dev_err(dev, "%s - Out of memory\n", __func__);
return;
}
snprintf(rfkn, 20, "hso-%d",
interface->altsetting->desc.bInterfaceNumber);
hso_net->rfkill->name = rfkn;
hso_net->rfkill->state = RFKILL_STATE_UNBLOCKED;
hso_net->rfkill->data = hso_dev;
hso_net->rfkill->toggle_radio = hso_radio_toggle;
if (rfkill_register(hso_net->rfkill) < 0) {
hso_net->rfkill = rfkill_alloc(rfkn,
&interface_to_usbdev(interface)->dev,
RFKILL_TYPE_WWAN,
&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);
hso_net->rfkill->name = NULL;
rfkill_free(hso_net->rfkill);
hso_net->rfkill = NULL;
dev_err(dev, "%s - Failed to register rfkill\n", __func__);
return;
@ -3165,8 +3165,10 @@ static void hso_free_interface(struct usb_interface *interface)
hso_stop_net_device(network_table[i]);
cancel_work_sync(&network_table[i]->async_put_intf);
cancel_work_sync(&network_table[i]->async_get_intf);
if (rfk)
if (rfk) {
rfkill_unregister(rfk);
rfkill_destroy(rfk);
}
hso_free_net_device(network_table[i]);
}
}

View file

@ -333,11 +333,11 @@ config USB_ZD1201
config USB_NET_RNDIS_WLAN
tristate "Wireless RNDIS USB support"
depends on USB && WLAN_80211 && EXPERIMENTAL
depends on CFG80211
select USB_USBNET
select USB_NET_CDCETHER
select USB_NET_RNDIS_HOST
select WIRELESS_EXT
select CFG80211
---help---
This is a driver for wireless RNDIS devices.
These are USB based adapters found in devices such as:

View file

@ -91,6 +91,7 @@ struct ar9170_led {
struct led_classdev l;
char name[32];
unsigned int toggled;
bool last_state;
bool registered;
};
@ -101,7 +102,6 @@ enum ar9170_device_state {
AR9170_STOPPED,
AR9170_IDLE,
AR9170_STARTED,
AR9170_ASSOCIATED,
};
struct ar9170_rxstream_mpdu_merge {
@ -140,7 +140,7 @@ struct ar9170 {
struct work_struct filter_config_work;
u64 cur_mc_hash, want_mc_hash;
u32 cur_filter, want_filter;
unsigned int filter_changed;
unsigned long filter_changed;
unsigned int filter_state;
bool sniffer_enabled;
@ -195,7 +195,7 @@ struct ar9170_sta_info {
#define IS_STARTED(a) (a->state >= AR9170_STARTED)
#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_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_handle_tx_status(struct ar9170 *ar, struct sk_buff *skb,
bool update_statistics, u16 tx_status);
void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
/* MAC */
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_set_operating_mode(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_update_beacon(struct ar9170 *ar);
void ar9170_new_beacon(struct work_struct *work);

View file

@ -207,7 +207,8 @@ enum ar9170_cmd {
#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_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_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
struct ar9170_cmd_tx_status {
__le16 unkn;
u8 dst[ETH_ALEN];
__le32 rate;
__le16 status;
@ -394,6 +394,7 @@ struct ar9170_cmd_ba_failed_count {
struct ar9170_cmd_response {
u8 flag;
u8 type;
__le16 padding;
union {
struct ar9170_cmd_tx_status tx_status;

View file

@ -74,7 +74,7 @@ static void ar9170_update_leds(struct work_struct *work)
mutex_lock(&ar->mutex);
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;
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 *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);
}
@ -136,13 +142,14 @@ void ar9170_unregister_leds(struct ar9170 *ar)
{
int i;
cancel_delayed_work_sync(&ar->led_work);
for (i = 0; i < AR9170_NUM_LEDS; i++)
if (ar->leds[i].registered) {
led_classdev_unregister(&ar->leds[i].l);
ar->leds[i].registered = false;
ar->leds[i].toggled = 0;
}
cancel_delayed_work_sync(&ar->led_work);
}
int ar9170_register_leds(struct ar9170 *ar)

View file

@ -38,6 +38,55 @@
#include "ar9170.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)
{
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);
ar9170_regwrite_begin(ar);
ar9170_regwrite(AR9170_MAC_REG_AMPDU_SET, val);
ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val);
ar9170_regwrite_finish();
return ar9170_regwrite_result();
@ -398,10 +447,10 @@ int ar9170_update_beacon(struct ar9170 *ar)
/* XXX: use skb->cb info */
if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
((skb->len + 4) << (3+16)) + 0x0400);
((skb->len + 4) << (3 + 16)) + 0x0400);
else
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_ADDR, AR9170_BEACON_BUFFER_ADDRESS);

View file

@ -146,7 +146,6 @@ static struct ieee80211_channel ar9170_5ghz_chantable[] = {
{ \
.ht_supported = true, \
.cap = IEEE80211_HT_CAP_MAX_AMSDU | \
IEEE80211_HT_CAP_SM_PS | \
IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
IEEE80211_HT_CAP_SGI_40 | \
IEEE80211_HT_CAP_DSSSCCK40 | \
@ -344,7 +343,6 @@ static void ar9170_tx_status_janitor(struct work_struct *work)
if (unlikely(!IS_STARTED(ar)))
return ;
mutex_lock(&ar->mutex);
/* recycle the garbage back to mac80211... one by one. */
while ((skb = skb_dequeue(&ar->global_tx_status_waste))) {
#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)
queue_delayed_work(ar->hw->workqueue, &ar->tx_status_janitor,
msecs_to_jiffies(100));
mutex_unlock(&ar->mutex);
}
static void ar9170_handle_command_response(struct ar9170 *ar,
void *buf, u32 len)
void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
{
struct ar9170_cmd_response *cmd = (void *) buf;
@ -957,6 +952,8 @@ static int ar9170_op_start(struct ieee80211_hw *hw)
mutex_lock(&ar->mutex);
ar->filter_changed = 0;
/* reinitialize queues statistics */
memset(&ar->tx_stats, 0, sizeof(ar->tx_stats));
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);
mutex_lock(&ar->mutex);
cancel_delayed_work_sync(&ar->tx_status_janitor);
cancel_work_sync(&ar->filter_config_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);
@ -1306,11 +1303,6 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&ar->mutex);
if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) {
/* TODO */
err = 0;
}
if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
/* TODO */
err = 0;
@ -1344,15 +1336,21 @@ static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
}
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,
AR9170_RFI_NONE,
nl80211_to_ar9170(hw->conf.channel_type));
if (err)
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:
@ -1370,20 +1368,26 @@ static void ar9170_set_filters(struct work_struct *work)
return ;
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);
if (err)
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);
if (err)
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);
if (err)
goto unlock;
}
unlock:
mutex_unlock(&ar->mutex);
@ -1413,7 +1417,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
int i;
/* always get broadcast frames */
mchash = 1ULL << (0xff>>2);
mchash = 1ULL << (0xff >> 2);
for (i = 0; i < mc_count; i++) {
if (WARN_ON(!mclist))
@ -1423,7 +1427,7 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
}
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) {
@ -1439,12 +1443,14 @@ static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
else
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) {
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)))
@ -1464,27 +1470,32 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_BSSID) {
memcpy(ar->bssid, bss_conf->bssid, ETH_ALEN);
err = ar9170_set_operating_mode(ar);
if (err)
goto out;
}
if (changed & (BSS_CHANGED_BEACON | BSS_CHANGED_BEACON_ENABLED)) {
err = ar9170_update_beacon(ar);
if (!err)
ar9170_set_beacon_timers(ar);
if (err)
goto out;
err = ar9170_set_beacon_timers(ar);
if (err)
goto out;
}
ar9170_regwrite_begin(ar);
if (changed & BSS_CHANGED_ASSOC) {
ar->state = bss_conf->assoc ? AR9170_ASSOCIATED : ar->state;
#ifndef CONFIG_AR9170_LEDS
/* enable assoc LED. */
err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0);
#endif /* CONFIG_AR9170_LEDS */
}
if (changed & BSS_CHANGED_BEACON_INT)
if (changed & BSS_CHANGED_BEACON_INT) {
err = ar9170_set_beacon_timers(ar);
if (err)
goto out;
}
if (changed & BSS_CHANGED_HT) {
/* TODO */
@ -1492,31 +1503,18 @@ static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_ERP_SLOT) {
u32 slottime = 20;
if (bss_conf->use_short_slot)
slottime = 9;
ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, slottime << 10);
err = ar9170_set_slot_time(ar);
if (err)
goto out;
}
if (changed & BSS_CHANGED_BASIC_RATES) {
u32 cck, ofdm;
if (hw->conf.channel->band == IEEE80211_BAND_5GHZ) {
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);
err = ar9170_set_basic_rates(ar);
if (err)
goto out;
}
ar9170_regwrite_finish();
err = ar9170_regwrite_result();
out:
mutex_unlock(&ar->mutex);
}

View file

@ -401,7 +401,7 @@ int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
int i, err;
u32 val;
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);
@ -1200,7 +1200,7 @@ int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
return -ENOSYS;
}
if (0 /* 2 streams capable */)
if (ar->eeprom.tx_mask != 1)
tmp |= 0x100;
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);
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[3] = cpu_to_le32(freqpar->coeff_exp);
vals[4] = cpu_to_le32(freqpar->coeff_man);

View file

@ -51,9 +51,14 @@ MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless");
MODULE_FIRMWARE("ar9170.fw");
MODULE_FIRMWARE("ar9170-1.fw");
MODULE_FIRMWARE("ar9170-2.fw");
enum ar9170_requirements {
AR9170_REQ_FW1_ONLY = 1,
};
static struct usb_device_id ar9170_usb_ids[] = {
/* Atheros 9170 */
{ USB_DEVICE(0x0cf3, 0x9170) },
@ -81,6 +86,10 @@ static struct usb_device_id ar9170_usb_ids[] = {
{ USB_DEVICE(0x2019, 0x5304) },
/* IO-Data WNGDNUS2 */
{ 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 */
{}
@ -93,7 +102,7 @@ static void ar9170_usb_tx_urb_complete_free(struct urb *urb)
struct ar9170_usb *aru = (struct ar9170_usb *)
usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
if (!aru) {
if (unlikely(!aru)) {
dev_kfree_skb_irq(skb);
return ;
}
@ -126,8 +135,8 @@ static void ar9170_usb_irq_completed(struct urb *urb)
goto resubmit;
}
print_hex_dump_bytes("ar9170 irq: ", DUMP_PREFIX_OFFSET,
urb->transfer_buffer, urb->actual_length);
ar9170_handle_command_response(&aru->common, urb->transfer_buffer,
urb->actual_length);
resubmit:
usb_anchor_urb(urb, &aru->rx_submitted);
@ -177,16 +186,15 @@ resubmit:
usb_anchor_urb(urb, &aru->rx_submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
if (unlikely(err)) {
usb_unanchor_urb(urb);
dev_kfree_skb_irq(skb);
goto free;
}
return ;
free:
dev_kfree_skb_irq(skb);
return;
}
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);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
if (unlikely(err)) {
usb_unanchor_urb(urb);
usb_free_urb(urb);
goto err_unbuf;
@ -418,7 +426,7 @@ static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer)
unsigned long flags;
u32 in, out;
if (!buffer)
if (unlikely(!buffer))
return ;
in = le32_to_cpup((__le32 *)buffer);
@ -504,17 +512,29 @@ static int ar9170_usb_request_firmware(struct ar9170_usb *aru)
{
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",
&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);
if (err) {
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;
}
@ -548,6 +568,9 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru)
{
int err;
if (!aru->init_values)
goto upload_fw_start;
/* First, upload initial values to device RAM */
err = ar9170_usb_upload(aru, aru->init_values->data,
aru->init_values->size, 0x102800, false);
@ -557,6 +580,8 @@ static int ar9170_usb_upload_firmware(struct ar9170_usb *aru)
return err;
}
upload_fw_start:
/* Then, upload the firmware itself and start it */
return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size,
0x200000, true);
@ -656,6 +681,15 @@ err_out:
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,
const struct usb_device_id *id)
{
@ -676,6 +710,8 @@ static int ar9170_usb_probe(struct usb_interface *intf,
aru->intf = intf;
ar = &aru->common;
aru->req_one_stage_fw = ar9170_requires_one_stage(id);
usb_set_intfdata(intf, aru);
SET_IEEE80211_DEV(ar->hw, &udev->dev);
@ -691,7 +727,7 @@ static int ar9170_usb_probe(struct usb_interface *intf,
#ifdef CONFIG_PM
udev->reset_resume = 1;
#endif
#endif /* CONFIG_PM */
err = ar9170_usb_reset(aru);
if (err)
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->tx_submitted);
/*
* FIXME: firmware upload will fail on resume.
* but this is better than a hang!
*/
err = ar9170_usb_init_device(aru);
if (err)
goto err_unrx;

View file

@ -62,6 +62,8 @@ struct ar9170_usb {
struct usb_anchor rx_submitted;
struct usb_anchor tx_submitted;
bool req_one_stage_fw;
spinlock_t cmdlock;
struct completion cmd_wait;
int readlen;

View file

@ -2070,6 +2070,13 @@ err_unmap:
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
* frame contents are done as needed and the slot time is
@ -2757,6 +2764,7 @@ ath5k_remove_interface(struct ieee80211_hw *hw,
goto end;
ath5k_hw_set_lladdr(sc->ah, mac);
ath5k_beacon_disable(sc);
sc->vif = NULL;
end:
mutex_unlock(&sc->lock);
@ -2775,11 +2783,9 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&sc->lock);
sc->bintval = conf->beacon_int;
ret = ath5k_chan_set(sc, conf->channel);
if (ret < 0)
return ret;
goto unlock;
if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
(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);
unlock:
mutex_unlock(&sc->lock);
return 0;
return ret;
}
#define SUPPORTED_FIF_FLAGS \
@ -3061,7 +3068,14 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
int ret;
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) {
ret = -ENOMEM;

View file

@ -460,12 +460,9 @@ struct ath_led {
bool registered;
};
/* Rfkill */
#define ATH_RFKILL_POLL_INTERVAL 2000 /* msecs */
struct ath_rfkill {
struct rfkill *rfkill;
struct delayed_work rfkill_poll;
struct rfkill_ops ops;
char rfkill_name[32];
};
@ -509,8 +506,6 @@ struct ath_rfkill {
#define SC_OP_RXFLUSH BIT(7)
#define SC_OP_LED_ASSOCIATED BIT(8)
#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_LED_ON BIT(13)
#define SC_OP_SCANNING BIT(14)

View file

@ -411,6 +411,7 @@ void ath_beacon_tasklet(unsigned long data)
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
DPRINTF(sc, ATH_DBG_BEACON,
"beacon is officially stuck\n");
sc->sc_flags |= SC_OP_TSF_RESET;
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;
/*
* 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 */
nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);

View file

@ -44,6 +44,44 @@ static int ath9k_debugfs_open(struct inode *inode, struct file *file)
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,
size_t count, loff_t *ppos)
{
@ -224,111 +262,66 @@ static const struct file_operations fops_interrupt = {
.owner = THIS_MODULE
};
static void ath_debug_stat_11n_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)
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;
struct ath_rc_stats *stats;
tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
final_ts_idx = tx_info_priv->tx.ts_rateindex;
idx = rates[final_ts_idx].idx;
sc->debug.stats.legacy_rcstats[idx].success++;
stats = &sc->debug.stats.rcstats[idx];
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,
int xretries, int retries, u8 per)
{
if (conf_is_ht(&sc->hw->conf)) {
int idx = sc->cur_rate_table->info[rix].dot11rate;
struct ath_rc_stats *stats = &sc->debug.stats.rcstats[rix];
sc->debug.stats.n_rcstats[idx].xretries += xretries;
sc->debug.stats.n_rcstats[idx].retries += retries;
sc->debug.stats.n_rcstats[idx].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);
stats->xretries += xretries;
stats->retries += retries;
stats->per = per;
}
static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
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)
return 0;
if (conf_is_ht(&sc->hw->conf))
return ath_read_file_stat_11n_rc(file, user_buf, count, ppos);
else
return ath_read_file_stat_legacy_rc(file, user_buf, count ,ppos);
max = 80 + sc->cur_rate_table->rate_cnt * 64;
buf = kmalloc(max + 1, GFP_KERNEL);
if (buf == NULL)
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 = {
@ -506,6 +499,11 @@ int ath9k_init_debug(struct ath_softc *sc)
if (!sc->debug.debugfs_phy)
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_phy, sc, &fops_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_interrupt);
debugfs_remove(sc->debug.debugfs_dma);
debugfs_remove(sc->debug.debugfs_debug);
debugfs_remove(sc->debug.debugfs_phy);
}

View file

@ -80,11 +80,7 @@ struct ath_interrupt_stats {
u32 dtim;
};
struct ath_legacy_rc_stats {
u32 success;
};
struct ath_11n_rc_stats {
struct ath_rc_stats {
u32 success;
u32 retries;
u32 xretries;
@ -93,13 +89,13 @@ struct ath_11n_rc_stats {
struct ath_stats {
struct ath_interrupt_stats istats;
struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */
struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */
struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
};
struct ath9k_debug {
int debug_mask;
struct dentry *debugfs_phy;
struct dentry *debugfs_debug;
struct dentry *debugfs_dma;
struct dentry *debugfs_interrupt;
struct dentry *debugfs_rcstat;

View file

@ -1192,120 +1192,69 @@ static bool ath_is_rfkill_set(struct ath_softc *sc)
ah->rfkill_polarity;
}
/* h/w rfkill poll function */
static void ath_rfkill_poll(struct work_struct *work)
{
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)
/* s/w rfkill handlers */
static int ath_rfkill_set_block(void *data, bool blocked)
{
struct ath_softc *sc = data;
switch (state) {
case RFKILL_STATE_SOFT_BLOCKED:
if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED |
SC_OP_RFKILL_SW_BLOCKED)))
ath_radio_disable(sc);
sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED;
return 0;
case RFKILL_STATE_UNBLOCKED:
if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) {
sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED;
if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) {
DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the"
"radio as it is disabled by h/w\n");
return -EPERM;
}
ath_radio_enable(sc);
}
return 0;
default:
return -EINVAL;
}
if (blocked)
ath_radio_disable(sc);
else
ath_radio_enable(sc);
return 0;
}
static void ath_rfkill_poll_state(struct rfkill *rfkill, void *data)
{
struct ath_softc *sc = data;
bool blocked = !!ath_is_rfkill_set(sc);
if (rfkill_set_hw_state(rfkill, blocked))
ath_radio_disable(sc);
else
ath_radio_enable(sc);
}
/* Init s/w rfkill */
static int ath_init_sw_rfkill(struct ath_softc *sc)
{
sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy),
RFKILL_TYPE_WLAN);
sc->rf_kill.ops.set_block = ath_rfkill_set_block;
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) {
DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
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;
}
/* Deinitialize rfkill */
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) {
rfkill_unregister(sc->rf_kill.rfkill);
rfkill_destroy(sc->rf_kill.rfkill);
sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED;
sc->rf_kill.rfkill = NULL;
}
}
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 (rfkill_register(sc->rf_kill.rfkill)) {
DPRINTF(sc, ATH_DBG_FATAL,
"Unable to register rfkill\n");
rfkill_free(sc->rf_kill.rfkill);
rfkill_destroy(sc->rf_kill.rfkill);
/* Deinitialize the device */
ath_cleanup(sc);
@ -1678,10 +1627,6 @@ int ath_attach(u16 devid, struct ath_softc *sc)
goto error_attach;
#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 */
error = ath_init_sw_rfkill(sc);
if (error)
@ -2214,10 +2159,8 @@ static void ath9k_stop(struct ieee80211_hw *hw)
} else
sc->rx.rxlink = NULL;
#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
rfkill_pause_polling(sc->rf_kill.rfkill);
/* disable HAL and put h/w to sleep */
ath9k_hw_disable(sc->sc_ah);
ath9k_hw_configpcipowersave(sc->sc_ah, 1);

View file

@ -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);
#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_disable_device(pdev);
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);
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;
}

View file

@ -366,11 +366,17 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
if (rd & COUNTRY_ERD_FLAG) {
/* EEPROM value is a country code */
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++)
if (allCountries[i].countryCode == cc)
return true;
} else {
/* 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++)
if (regDomainPairs[i].regDmnEnum == rd)
return true;
@ -477,6 +483,11 @@ ath_regd_init(struct ath_regulatory *reg,
struct country_code_to_enum_rd *country = NULL;
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)) {
printk(KERN_ERR "ath: Invalid EEPROM contents\n");
return -EINVAL;
@ -486,20 +497,30 @@ ath_regd_init(struct ath_regulatory *reg,
reg->country_code = ath_regd_get_default_country(regdmn);
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;
}
if (reg->country_code == CTRY_DEFAULT) {
country = NULL;
} else {
printk(KERN_DEBUG "ath: doing EEPROM country->regdmn "
"map search\n");
country = ath_regd_find_country(reg->country_code);
if (country == NULL) {
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);
return -EINVAL;
} else
} else {
regdmn = country->regDmnEnum;
printk(KERN_DEBUG "ath: country maps to "
"regdmn code: 0x%0x\n",
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",
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);
ath_regd_init_wiphy(reg, wiphy, reg_notifier);

View file

@ -102,7 +102,7 @@ config B43_LEDS
# if it's possible.
config B43_RFKILL
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
# This config option automatically enables b43 HW-RNG support,

View file

@ -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,
const char *name, char *default_trigger,
const char *name, const char *default_trigger,
u8 led_index, bool activelow)
{
int err;

View file

@ -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) {
b43_software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
b43_software_rfkill(dev, false);
b43info(dev->wl, "Radio turned on by software\n");
if (!dev->radio_hw_enable) {
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");
}
} else {
b43_software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
b43_software_rfkill(dev, true);
b43info(dev->wl, "Radio turned off by software\n");
}
}

View file

@ -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,
enum rfkill_state state)
bool blocked)
{
struct b43_phy *phy = &dev->phy;
if (state == RFKILL_STATE_UNBLOCKED) {
if (!blocked) {
if (phy->radio_on)
return;
b43_radio_write16(dev, 0x0004, 0x00C0);

View file

@ -84,7 +84,7 @@ int b43_phy_init(struct b43_wldev *dev)
phy->channel = ops->get_default_chan(dev);
ops->software_rfkill(dev, RFKILL_STATE_UNBLOCKED);
ops->software_rfkill(dev, false);
err = ops->init(dev);
if (err) {
b43err(dev->wl, "PHY init failed\n");
@ -104,7 +104,7 @@ err_phy_exit:
if (ops->exit)
ops->exit(dev);
err_block_rf:
ops->software_rfkill(dev, RFKILL_STATE_SOFT_BLOCKED);
ops->software_rfkill(dev, true);
return err;
}
@ -113,7 +113,7 @@ void b43_phy_exit(struct b43_wldev *dev)
{
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)
ops->exit(dev);
}
@ -295,18 +295,13 @@ err_restore_cookie:
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;
if (state == RFKILL_STATE_HARD_BLOCKED) {
/* We cannot hardware-block the device */
state = RFKILL_STATE_SOFT_BLOCKED;
}
b43_mac_suspend(dev);
phy->ops->software_rfkill(dev, state);
phy->radio_on = (state == RFKILL_STATE_UNBLOCKED);
phy->ops->software_rfkill(dev, blocked);
phy->radio_on = !blocked;
b43_mac_enable(dev);
}

View file

@ -159,7 +159,7 @@ struct b43_phy_operations {
/* Radio */
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);
int (*switch_channel)(struct b43_wldev *dev, unsigned int new_channel);
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.
*/
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.

View file

@ -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,
enum rfkill_state state)
bool blocked)
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
@ -2600,7 +2600,7 @@ static void b43_gphy_op_software_rfkill(struct b43_wldev *dev,
might_sleep();
if (state == RFKILL_STATE_UNBLOCKED) {
if (!blocked) {
/* Turn radio ON */
if (phy->radio_on)
return;

View file

@ -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,
enum rfkill_state state)
bool blocked)
{
//TODO
}

View file

@ -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,
enum rfkill_state state)
bool blocked)
{//TODO
}

View file

@ -45,12 +45,11 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
}
/* 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;
bool enabled;
bool report_change = 0;
mutex_lock(&wl->mutex);
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);
if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled;
report_change = 1;
b43info(wl, "Radio hardware status changed to %s\n",
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);
/* 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. */
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_wl *wl = dev->wl;
int err = -EBUSY;
int err = -EINVAL;
if (!wl->rfkill.registered)
return 0;
if (WARN_ON(!wl->rfkill.registered))
return -EINVAL;
mutex_lock(&wl->mutex);
if (b43_status(dev) < B43_STAT_INITIALIZED)
goto out_unlock;
if (!dev->radio_hw_enable)
goto out_unlock;
if (!blocked != dev->phy.radio_on)
b43_software_rfkill(dev, blocked);
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:
mutex_unlock(&wl->mutex);
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);
if (!rfk->registered)
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)
{
struct b43_wl *wl = dev->wl;
@ -130,65 +116,26 @@ void b43_rfkill_init(struct b43_wldev *dev)
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),
"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();
if (!rfk->poll_dev) {
rfkill_free(rfk->rfkill);
goto err_freed_rfk;
}
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);
rfk->rfkill = rfkill_alloc(rfk->name,
dev->dev->dev,
RFKILL_TYPE_WLAN,
&b43_rfkill_ops, dev);
if (!rfk->rfkill)
goto out_error;
err = rfkill_register(rfk->rfkill);
if (err)
goto err_free_polldev;
#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;
goto err_free;
rfk->registered = 1;
return;
err_unreg_rfk:
rfkill_unregister(rfk->rfkill);
err_free_polldev:
input_free_polled_device(rfk->poll_dev);
rfk->poll_dev = NULL;
err_freed_rfk:
rfk->rfkill = NULL;
out_error:
err_free:
rfkill_destroy(rfk->rfkill);
out_error:
rfk->registered = 0;
b43warn(wl, "RF-kill button init failed\n");
}
@ -201,9 +148,7 @@ void b43_rfkill_exit(struct b43_wldev *dev)
return;
rfk->registered = 0;
input_unregister_polled_device(rfk->poll_dev);
rfkill_unregister(rfk->rfkill);
input_free_polled_device(rfk->poll_dev);
rfk->poll_dev = NULL;
rfkill_destroy(rfk->rfkill);
rfk->rfkill = NULL;
}

View file

@ -7,14 +7,11 @@ struct b43_wldev;
#ifdef CONFIG_B43_RFKILL
#include <linux/rfkill.h>
#include <linux/input-polldev.h>
struct b43_rfkill {
/* The RFKILL subsystem data structure */
struct rfkill *rfkill;
/* The poll device for the RFKILL input button */
struct input_polled_dev *poll_dev;
/* Did initialization succeed? Used for freeing. */
bool registered;
/* 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_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 */

View file

@ -47,7 +47,7 @@ config B43LEGACY_LEDS
# if it's possible.
config B43LEGACY_RFKILL
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
# This config option automatically enables b43 HW-RNG support,

View file

@ -86,7 +86,8 @@ static void b43legacy_led_brightness_set(struct led_classdev *led_dev,
static int b43legacy_register_led(struct b43legacy_wldev *dev,
struct b43legacy_led *led,
const char *name, char *default_trigger,
const char *name,
const char *default_trigger,
u8 led_index, bool activelow)
{
int err;

View file

@ -45,12 +45,11 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
}
/* 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;
bool enabled;
bool report_change = 0;
mutex_lock(&wl->mutex);
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);
if (unlikely(enabled != dev->radio_hw_enable)) {
dev->radio_hw_enable = enabled;
report_change = 1;
b43legacyinfo(wl, "Radio hardware status changed to %s\n",
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);
/* 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.
* 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_wl *wl = dev->wl;
int err = -EBUSY;
int ret = -EINVAL;
if (!wl->rfkill.registered)
return 0;
return -EINVAL;
mutex_lock(&wl->mutex);
if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
goto out_unlock;
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)
if (!dev->radio_hw_enable)
goto out_unlock;
if (!blocked != dev->phy.radio_on) {
if (!blocked)
b43legacy_radio_turn_on(dev);
break;
case RFKILL_STATE_SOFT_BLOCKED:
if (dev->phy.radio_on)
else
b43legacy_radio_turn_off(dev, 0);
break;
default:
b43legacywarn(wl, "Received unexpected rfkill state %d.\n",
state);
break;
}
ret = 0;
out_unlock:
mutex_unlock(&wl->mutex);
return err;
return ret;
}
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);
if (!rfk->registered)
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)
{
struct b43legacy_wl *wl = dev->wl;
@ -133,60 +125,25 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
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),
"b43legacy-%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 = b43legacy_rfkill_soft_toggle;
rfk->poll_dev = input_allocate_polled_device();
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);
rfk->rfkill = rfkill_alloc(rfk->name,
dev->dev->dev,
RFKILL_TYPE_WLAN,
&b43legacy_rfkill_ops, dev);
if (!rfk->rfkill)
goto out_error;
err = rfkill_register(rfk->rfkill);
if (err)
goto err_free_polldev;
#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;
goto err_free;
rfk->registered = 1;
return;
err_unreg_rfk:
rfkill_unregister(rfk->rfkill);
err_free_polldev:
input_free_polled_device(rfk->poll_dev);
rfk->poll_dev = NULL;
err_freed_rfk:
rfk->rfkill = NULL;
out_error:
err_free:
rfkill_destroy(rfk->rfkill);
out_error:
rfk->registered = 0;
b43legacywarn(wl, "RF-kill button init failed\n");
}
@ -199,10 +156,8 @@ void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
return;
rfk->registered = 0;
input_unregister_polled_device(rfk->poll_dev);
rfkill_unregister(rfk->rfkill);
input_free_polled_device(rfk->poll_dev);
rfk->poll_dev = NULL;
rfkill_destroy(rfk->rfkill);
rfk->rfkill = NULL;
}

View file

@ -6,16 +6,12 @@ struct b43legacy_wldev;
#ifdef CONFIG_B43LEGACY_RFKILL
#include <linux/rfkill.h>
#include <linux/workqueue.h>
#include <linux/input-polldev.h>
struct b43legacy_rfkill {
/* The RFKILL subsystem data structure */
struct rfkill *rfkill;
/* The poll device for the RFKILL input button */
struct input_polled_dev *poll_dev;
/* Did initialization succeed? Used for freeing. */
bool registered;
/* 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_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 */

View file

@ -5,15 +5,14 @@ config IWLWIFI
select FW_LOADER
select MAC80211_LEDS if IWLWIFI_LEDS
select LEDS_CLASS if IWLWIFI_LEDS
select RFKILL if IWLWIFI_RFKILL
config IWLWIFI_LEDS
bool "Enable LED support in iwlagn and iwl3945 drivers"
depends on IWLWIFI
config IWLWIFI_RFKILL
bool "Enable RF kill support in iwlagn and iwl3945 drivers"
depends on IWLWIFI
def_bool y
depends on IWLWIFI && RFKILL
config IWLWIFI_SPECTRUM_MEASUREMENT
bool "Enable Spectrum Measurement in iwlagn driver"

View file

@ -167,10 +167,6 @@ static int iwl3945_led_disassociate(struct iwl_priv *priv, int led_id)
IWL_DEBUG_LED(priv, "Disassociated\n");
priv->allow_blinking = 0;
if (iwl_is_rfkill(priv))
iwl3945_led_off(priv, led_id);
else
iwl3945_led_on(priv, led_id);
return 0;
}

View file

@ -38,6 +38,7 @@
#include "iwl-commands.h"
#include "iwl-3945.h"
#include "iwl-sta.h"
#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) &&
!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) {
IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n",
hdr->addr1);
sta_id = iwl3945_add_station(priv,
hdr->addr1, 0, CMD_ASYNC, NULL);
sta_id = iwl_add_station(priv, hdr->addr1, false,
CMD_ASYNC, NULL);
}
if (sta_id != IWL_INVALID_STATION)
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();
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) {
rcu_read_unlock();
return;

View file

@ -769,35 +769,6 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
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:
*
@ -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)
{
unsigned long flags_spin;
struct iwl3945_station_entry *station;
struct iwl_station_entry *station;
if (sta_id == IWL_INVALID_STATION)
return IWL_INVALID_STATION;
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.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);
iwl_send_add_sta(priv,
(struct iwl_addsta_cmd *)&station->sta, flags);
iwl_send_add_sta(priv, &station->sta, flags);
IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n",
sta_id, tx_rate);
return sta_id;
@ -2029,7 +1999,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
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
* 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 */
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_ERR(priv, "Error adding BROADCAST address for transmit.\n");
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 */
if (iwl_is_associated(priv) &&
(priv->iw_mode == NL80211_IFTYPE_STATION))
if (priv->cfg->ops->smgmt->add_station(priv,
priv->active_rxon.bssid_addr, 1, 0, NULL)
== IWL_INVALID_STATION) {
if (iwl_add_station(priv, priv->active_rxon.bssid_addr,
true, CMD_SYNC, NULL) == IWL_INVALID_STATION) {
IWL_ERR(priv, "Error adding AP address for transmit\n");
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)
{
u16 size = (u16)sizeof(struct iwl3945_addsta_cmd);
memcpy(data, cmd, size);
return size;
struct iwl3945_addsta_cmd *addsta = (struct iwl3945_addsta_cmd *)data;
addsta->mode = cmd->mode;
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
*/
@ -2842,15 +2823,6 @@ static struct iwl_lib_ops iwl3945_lib = {
.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 = {
.get_hcmd_size = iwl3945_get_hcmd_size,
.build_addsta_hcmd = iwl3945_build_addsta_hcmd,
@ -2860,7 +2832,6 @@ static struct iwl_ops iwl3945_ops = {
.lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
.smgmt = &iwl3945_station_mgmt,
};
static struct iwl_cfg iwl3945_bg_cfg = {

View file

@ -202,12 +202,6 @@ struct iwl3945_ibss_seq {
* 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_eeprom_init(struct iwl_priv *priv);
extern int iwl3945_calc_db_from_ratio(int sig_ratio);

View file

@ -2221,13 +2221,6 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
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 = {
.rxon_assoc = iwl4965_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
@ -2297,7 +2290,6 @@ static struct iwl_ops iwl4965_ops = {
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
.smgmt = &iwl4965_station_mgmt,
};
struct iwl_cfg iwl4965_agn_cfg = {

View file

@ -651,7 +651,7 @@ static void iwl5000_init_alive_start(struct iwl_priv *priv)
goto restart;
}
priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_clear_stations_table(priv);
ret = priv->cfg->ops->lib->alive_notify(priv);
if (ret) {
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 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;
}
@ -1423,13 +1426,6 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
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 = {
.rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
@ -1549,14 +1545,12 @@ struct iwl_ops iwl5000_ops = {
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
.smgmt = &iwl5000_station_mgmt,
};
static struct iwl_ops iwl5150_ops = {
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
.smgmt = &iwl5000_station_mgmt,
};
struct iwl_mod_params iwl50_mod_params = {

View file

@ -72,7 +72,6 @@ static struct iwl_ops iwl6000_ops = {
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl6000_hcmd_utils,
.smgmt = &iwl5000_station_mgmt,
};
struct iwl_cfg iwl6000_2ag_cfg = {

View file

@ -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) &&
!lq_sta->ibss_sta_added) {
u8 sta_id = priv->cfg->ops->smgmt->find_station(priv,
hdr->addr1);
u8 sta_id = iwl_find_station(priv, hdr->addr1);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
hdr->addr1);
sta_id = priv->cfg->ops->smgmt->add_station(priv,
hdr->addr1, 0,
CMD_ASYNC, NULL);
sta_id = iwl_add_station(priv, hdr->addr1,
false, CMD_ASYNC, NULL);
}
if ((sta_id != IWL_INVALID_STATION)) {
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;
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);
/* 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) {
IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n", sta->addr);
sta_id = priv->cfg->ops->smgmt->add_station(priv,
sta->addr, 0,
CMD_ASYNC, NULL);
sta_id = iwl_add_station(priv, sta->addr, false,
CMD_ASYNC, NULL);
}
if ((sta_id != IWL_INVALID_STATION)) {
lq_sta->lq.sta_id = sta_id;
@ -2790,9 +2787,10 @@ static void rs_fill_link_cmd(const struct iwl_priv *priv,
repeat_rate--;
}
lq_cmd->agg_params.agg_frame_cnt_limit = 64;
lq_cmd->agg_params.agg_dis_start_th = 3;
lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
lq_cmd->agg_params.agg_frame_cnt_limit = LINK_QUAL_AGG_FRAME_LIMIT_MAX;
lq_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
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)

View file

@ -188,7 +188,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
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;
@ -1617,7 +1617,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
goto restart;
}
priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_clear_stations_table(priv);
ret = priv->cfg->ops->lib->alive_notify(priv);
if (ret) {
IWL_WARN(priv,
@ -1703,7 +1703,7 @@ static void __iwl_down(struct iwl_priv *priv)
iwl_leds_unregister(priv);
priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_clear_stations_table(priv);
/* Unblock any waiting calls */
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 */
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
/* enable dram interrupt */
iwl_reset_ict(priv);
iwl_enable_interrupts(priv);
/* 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++) {
priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_clear_stations_table(priv);
/* load bootstrap state machine,
* 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))
return;
/* enable dram interrupt */
iwl_reset_ict(priv);
mutex_lock(&priv->mutex);
iwl_alive_start(priv);
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;
}
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) {
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
addr);
@ -3121,7 +3122,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_rx_queue_free(priv, &priv->rxq);
iwl_hw_txq_ctx_free(priv);
priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_clear_stations_table(priv);
iwl_eeprom_free(priv);

View file

@ -1067,7 +1067,7 @@ struct iwl_addsta_cmd {
* Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
__le16 tid_disable_tx;
__le16 reserved1;
__le16 rate_n_flags; /* 3945 only */
/* TID for which to add block-ack support.
* 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];
} __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
*

View file

@ -1389,7 +1389,7 @@ int iwl_init_drv(struct iwl_priv *priv)
mutex_init(&priv->mutex);
/* 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->ieee_channels = NULL;
@ -1704,8 +1704,9 @@ static irqreturn_t iwl_isr(int irq, void *data)
{
struct iwl_priv *priv = data;
u32 inta, inta_mask;
#ifdef CONFIG_IWLWIFI_DEBUG
u32 inta_fh;
#endif
if (!priv)
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);
priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_clear_stations_table(priv);
/* dont commit rxon if rf-kill is on*/
if (!iwl_is_ready_rf(priv))
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);
return 0;

View file

@ -83,15 +83,6 @@ struct iwl_cmd;
#define IWL_SKU_A 0x2
#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 {
int (*rxon_assoc)(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_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
const struct iwl_station_mgmt_ops *smgmt;
};
struct iwl_mod_params {
@ -192,7 +182,7 @@ struct iwl_mod_params {
int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_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 antenna; /* def: 0 = both antennas (use diversity) */
int restart_fw; /* def: 1 = restart firmware */

View file

@ -70,7 +70,6 @@ extern struct iwl_ops iwl5000_ops;
extern struct iwl_lib_ops iwl5000_lib;
extern struct iwl_hcmd_ops iwl5000_hcmd;
extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
extern struct iwl_station_mgmt_ops iwl5000_station_mgmt;
/* shared functions from iwl-5000.c */
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)
enum {
/* CMD_SIZE_NORMAL = 0, */
CMD_SYNC = 0,
CMD_SIZE_NORMAL = 0,
CMD_NO_SKB = 0,
CMD_SIZE_HUGE = (1 << 0),
/* CMD_SYNC = 0, */
CMD_ASYNC = (1 << 1),
/* CMD_NO_SKB = 0, */
CMD_WANT_SKB = (1 << 2),
};
@ -1119,8 +1118,6 @@ struct iwl_priv {
struct iwl3945_notif_statistics statistics_39;
struct iwl3945_station_entry stations_39[IWL_STATION_COUNT];
u32 sta_supp_rates;
}; /*iwl_priv */

View file

@ -240,13 +240,11 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
if (ret < 0)
IWL_ERR(priv, "Time out access OTP\n");
else {
if (!ret) {
iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
udelay(5);
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
}
iwl_set_bits_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
udelay(5);
iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG,
APMG_PS_CTRL_VAL_RESET_REQ);
}
return ret;
}

View file

@ -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)
{
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;
}

View file

@ -36,42 +36,37 @@
#include "iwl-core.h"
/* 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;
int err = 0;
if (!priv->rfkill)
return 0;
return -EINVAL;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
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);
switch (state) {
case RFKILL_STATE_UNBLOCKED:
if (iwl_is_rfkill_hw(priv)) {
err = -EBUSY;
goto out_unlock;
}
if (iwl_is_rfkill_hw(priv))
goto out_unlock;
if (!blocked)
iwl_radio_kill_sw_enable_radio(priv);
break;
case RFKILL_STATE_SOFT_BLOCKED:
else
iwl_radio_kill_sw_disable_radio(priv);
break;
default:
IWL_WARN(priv, "we received unexpected RFKILL state %d\n",
state);
break;
}
out_unlock:
mutex_unlock(&priv->mutex);
return err;
return 0;
}
static const struct rfkill_ops iwl_rfkill_ops = {
.set_block = iwl_rfkill_soft_rf_kill,
};
int iwl_rfkill_init(struct iwl_priv *priv)
{
struct device *device = wiphy_dev(priv->hw->wiphy);
@ -80,21 +75,16 @@ int iwl_rfkill_init(struct iwl_priv *priv)
BUG_ON(device == NULL);
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) {
IWL_ERR(priv, "Unable to allocate RFKILL device.\n");
ret = -ENOMEM;
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);
if (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");
return ret;
return 0;
free_rfkill:
if (priv->rfkill != NULL)
rfkill_free(priv->rfkill);
rfkill_destroy(priv->rfkill);
priv->rfkill = NULL;
error:
@ -118,8 +107,10 @@ EXPORT_SYMBOL(iwl_rfkill_init);
void iwl_rfkill_unregister(struct iwl_priv *priv)
{
if (priv->rfkill)
if (priv->rfkill) {
rfkill_unregister(priv->rfkill);
rfkill_destroy(priv->rfkill);
}
priv->rfkill = NULL;
}
@ -131,14 +122,10 @@ void iwl_rfkill_set_hw_state(struct iwl_priv *priv)
if (!priv->rfkill)
return;
if (iwl_is_rfkill_hw(priv)) {
rfkill_force_state(priv->rfkill, RFKILL_STATE_HARD_BLOCKED);
return;
}
if (!iwl_is_rfkill_sw(priv))
rfkill_force_state(priv->rfkill, RFKILL_STATE_UNBLOCKED);
if (rfkill_set_hw_state(priv->rfkill,
!!iwl_is_rfkill_hw(priv)))
iwl_radio_kill_sw_disable_radio(priv);
else
rfkill_force_state(priv->rfkill, RFKILL_STATE_SOFT_BLOCKED);
iwl_radio_kill_sw_enable_radio(priv);
}
EXPORT_SYMBOL(iwl_rfkill_set_hw_state);

View file

@ -75,7 +75,7 @@ int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
return IWL_AP_ID;
} else {
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);
@ -86,8 +86,7 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
spin_lock_irqsave(&priv->sta_lock, flags);
if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) &&
!(priv->stations_39[sta_id].used & IWL_STA_DRIVER_ACTIVE))
if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE))
IWL_ERR(priv, "ACTIVATE a non DRIVER active station %d\n",
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 flags, struct ieee80211_sta_ht_cap *ht_info)
u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
struct ieee80211_sta_ht_cap *ht_info)
{
int i;
int sta_id = IWL_INVALID_STATION;
struct iwl_station_entry *station;
unsigned long flags_spin;
int i;
int sta_id = IWL_INVALID_STATION;
u16 rate;
spin_lock_irqsave(&priv->sta_lock, flags_spin);
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)
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);
/* 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;
}
EXPORT_SYMBOL(iwl_add_station_flags);
EXPORT_SYMBOL(iwl_add_station);
static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr)
{
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);
@ -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.
*/
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 i, ret = -EINVAL;
@ -767,7 +773,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
unsigned long flags;
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) {
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
addr);
@ -946,7 +952,7 @@ EXPORT_SYMBOL(iwl_send_lq_cmd);
* calling this function (which runs REPLY_TX_LINK_QUALITY_CMD,
* 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;
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 =
first_antenna(priv->hw_params.valid_tx_ant);
link_cmd.general_params.dual_stream_ant_msk = 3;
link_cmd.agg_params.agg_dis_start_th = 3;
link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
link_cmd.agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
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 */
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
* 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_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();
}
sta_id = priv->cfg->ops->smgmt->add_station(priv, addr, is_ap,
0, cur_ht_config);
sta_id = iwl_add_station(priv, addr, is_ap, CMD_SYNC, cur_ht_config);
/* Set up default rate scaling table in device's station table */
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 */
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)
return 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,
* or create a new station table entry */
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)
return sta_id;
/* Create new station table entry */
sta_id = priv->cfg->ops->smgmt->add_station(priv, hdr->addr1,
0, CMD_ASYNC, NULL);
sta_id = iwl_add_station(priv, hdr->addr1, false,
CMD_ASYNC, NULL);
if (sta_id != IWL_INVALID_STATION)
return sta_id;
@ -1111,7 +1117,7 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv,
unsigned long flags;
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)
return -ENXIO;
@ -1133,7 +1139,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid)
unsigned long flags;
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) {
IWL_ERR(priv, "Invalid station for AGG tid %d\n", tid);
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)
{
/* 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) {
u8 sta_awake = priv->stations[sta_id].

View file

@ -51,16 +51,15 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf,
const u8 *addr, u32 iv32, u16 *phase1key);
int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
int iwl_remove_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, bool is_ap);
void iwl_clear_stations_table(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_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_addsta_cmd *sta, u8 flags);
u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr,
int is_ap, u8 flags,
u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, bool is_ap, u8 flags,
struct ieee80211_sta_ht_cap *ht_info);
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,

View file

@ -95,144 +95,6 @@ struct iwl_mod_params iwl3945_mod_params = {
/* 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
* @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;
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations_39[sta_id].keyinfo.alg = keyconf->alg;
priv->stations_39[sta_id].keyinfo.keylen = keyconf->keylen;
memcpy(priv->stations_39[sta_id].keyinfo.key, keyconf->key,
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
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);
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)
priv->stations_39[sta_id].sta.key.key_offset =
priv->stations[sta_id].sta.key.key_offset =
iwl_get_free_ucode_key_index(priv);
/* else, we are overriding an existing key => no need to allocated room
* 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");
priv->stations_39[sta_id].sta.key.key_flags = key_flags;
priv->stations_39[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.key.key_flags = key_flags;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n");
ret = iwl_send_add_sta(priv,
(struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, CMD_ASYNC);
ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
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;
spin_lock_irqsave(&priv->sta_lock, flags);
memset(&priv->stations_39[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
memset(&priv->stations_39[sta_id].sta.key, 0,
memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
memset(&priv->stations[sta_id].sta.key, 0,
sizeof(struct iwl4965_keyinfo));
priv->stations_39[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_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
spin_unlock_irqrestore(&priv->sta_lock, flags);
IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n");
iwl_send_add_sta(priv,
(struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, 0);
iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0);
return 0;
}
@ -578,7 +438,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
int sta_id)
{
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) {
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)) {
qc = ieee80211_get_qos_ctl(hdr);
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;
hdr->seq_ctrl = cpu_to_le16(seq_number) |
(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)) {
txq->need_update = 1;
if (qc)
priv->stations_39[sta_id].tid[tid].seq_number = seq_number;
priv->stations[sta_id].tid[tid].seq_number = seq_number;
} else {
wait_write_ptr = 1;
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.
* 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)) {
spin_lock_irqsave(&rxq->lock, flags);
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.
* 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 list_head *element;
@ -1360,7 +1220,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv)
/* Alloc a new receive buffer */
rxb->skb =
alloc_skb(priv->hw_params.rx_buf_size,
GFP_KERNEL);
priority);
if (!rxb->skb) {
if (net_ratelimit())
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 */
rxq->read = rxq->write = 0;
rxq->free_count = 0;
rxq->write_actual = 0;
spin_unlock_irqrestore(&rxq->lock, flags);
}
@ -1427,13 +1288,21 @@ void iwl3945_rx_replenish(void *data)
struct iwl_priv *priv = data;
unsigned long flags;
iwl3945_rx_allocate(priv);
iwl3945_rx_allocate(priv, GFP_KERNEL);
spin_lock_irqsave(&priv->lock, flags);
iwl3945_rx_queue_restock(priv);
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.
* 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
@ -1556,13 +1425,19 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
unsigned long flags;
u8 fill_rx = 0;
u32 count = 8;
int total_empty = 0;
/* uCode's read index (stored in shared DRAM) indicates the last Rx
* buffer that the driver may process (last buffer filled by ucode). */
r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF;
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;
/* Rx interrupt, but nothing sent from uCode */
if (i == r)
@ -1639,7 +1514,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
count++;
if (count >= 8) {
priv->rxq.read = i;
iwl3945_rx_queue_restock(priv);
iwl3945_rx_replenish_now(priv);
count = 0;
}
}
@ -1647,7 +1522,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
/* Backtrack one entry */
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 */
@ -2589,7 +2467,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
goto restart;
}
priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_clear_stations_table(priv);
rfkill = iwl_read_prph(priv, APMG_RFKILL_REG);
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);
iwl3945_led_unregister(priv);
priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_clear_stations_table(priv);
/* Unblock any waiting calls */
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++) {
priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_clear_stations_table(priv);
/* load bootstrap state machine,
* load bootstrap program into processor's memory,
@ -3247,7 +3125,7 @@ void iwl3945_post_associate(struct iwl_priv *priv)
case NL80211_IFTYPE_ADHOC:
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,
(priv->band == IEEE80211_BAND_5GHZ) ?
IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
@ -3438,7 +3316,7 @@ void iwl3945_config_ap(struct iwl_priv *priv)
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
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);
@ -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);
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) {
IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
addr);
@ -4044,7 +3922,7 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
mutex_init(&priv->mutex);
/* 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->ieee_channels = NULL;
@ -4407,7 +4285,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
iwl3945_hw_txq_ctx_free(priv);
iwl3945_unset_hw_params(priv);
priv->cfg->ops->smgmt->clear_station_table(priv);
iwl_clear_stations_table(priv);
/*netif_stop_queue(dev); */
flush_workqueue(priv->workqueue);

View file

@ -1,10 +1,9 @@
config IWM
tristate "Intel Wireless Multicomm 3200 WiFi driver"
depends on MMC && WLAN_80211 && EXPERIMENTAL
depends on CFG80211
select WIRELESS_EXT
select CFG80211
select FW_LOADER
select RFKILL
config IWM_DEBUG
bool "Enable full debugging output in iwmc3200wifi"

View file

@ -1,5 +1,5 @@
obj-$(CONFIG_IWM) := iwmc3200wifi.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

View file

@ -268,7 +268,7 @@ static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
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,
iwm->conf.frag_threshold);
if (ret < 0)

View file

@ -72,7 +72,7 @@ static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw,
}
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;
}

View file

@ -343,8 +343,4 @@ int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size,
struct iwm_wifi_cmd *cmd);
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

View file

@ -136,17 +136,8 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
wdev->netdev = ndev;
ret = iwm_rfkill_init(iwm);
if (ret) {
dev_err(dev, "Failed to init rfkill\n");
goto out_rfkill;
}
return iwm;
out_rfkill:
unregister_netdev(ndev);
out_ndev:
free_netdev(ndev);
@ -162,7 +153,6 @@ void iwm_if_free(struct iwm_priv *iwm)
if (!iwm_to_ndev(iwm))
return;
iwm_rfkill_exit(iwm);
unregister_netdev(iwm_to_ndev(iwm));
free_netdev(iwm_to_ndev(iwm));
iwm_wdev_free(iwm);

View file

@ -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;
}

View file

@ -395,7 +395,7 @@ static struct iwm_if_ops if_sdio_ops = {
.debugfs_init = if_sdio_debugfs_init,
.debugfs_exit = if_sdio_debugfs_exit,
.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",
};

View file

@ -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_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
COUNTRY_CODE_LEN + 1 +
sizeof(struct ieeetypes_subbandset) * nr_subband);
sizeof(struct ieee_subbandset) * nr_subband);
return 0;
}
@ -302,11 +302,9 @@ done:
* @param parsed_region_chan pointer to parsed_region_chan_11d
* @return 0
*/
static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
countryinfo,
static int parse_domain_info_11d(struct ieee_ie_country_info_full_set *countryinfo,
u8 band,
struct parsed_region_chan_11d *
parsed_region_chan)
struct parsed_region_chan_11d *parsed_region_chan)
{
u8 nr_subband, nrchan;
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);
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 */
goto done;
}
@ -349,8 +347,8 @@ static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
COUNTRY_CODE_LEN);
nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
sizeof(struct ieeetypes_subbandset);
nr_subband = (countryinfo->header.len - COUNTRY_CODE_LEN) /
sizeof(struct ieee_subbandset);
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 =
&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;
lbs_deb_enter(LBS_DEB_11D);
@ -524,16 +522,16 @@ int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
sizeof(domain->countrycode));
domain->header.len =
cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
cpu_to_le16(nr_subband * sizeof(struct ieee_subbandset) +
sizeof(domain->countrycode));
if (nr_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) +
le16_to_cpu(domain->header.len) +
sizeof(struct mrvlietypesheader) +
sizeof(struct mrvl_ie_header) +
S_DS_GEN);
} else {
cmd->size =
@ -556,7 +554,7 @@ done:
int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
{
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);
s16 ret = 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));
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);

View file

@ -20,35 +20,36 @@
struct cmd_ds_command;
/** Data structure for Country IE*/
struct ieeetypes_subbandset {
struct ieee_subbandset {
u8 firstchan;
u8 nrchan;
u8 maxtxpwr;
} __attribute__ ((packed));
struct ieeetypes_countryinfoset {
u8 element_id;
u8 len;
struct ieee_ie_country_info_set {
struct ieee_ie_header header;
u8 countrycode[COUNTRY_CODE_LEN];
struct ieeetypes_subbandset subband[1];
struct ieee_subbandset subband[1];
};
struct ieeetypes_countryinfofullset {
u8 element_id;
u8 len;
struct ieee_ie_country_info_full_set {
struct ieee_ie_header header;
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));
struct mrvlietypes_domainparamset {
struct mrvlietypesheader header;
struct mrvl_ie_domain_param_set {
struct mrvl_ie_header header;
u8 countrycode[COUNTRY_CODE_LEN];
struct ieeetypes_subbandset subband[1];
struct ieee_subbandset subband[1];
} __attribute__ ((packed));
struct cmd_ds_802_11d_domain_info {
__le16 action;
struct mrvlietypes_domainparamset domain;
struct mrvl_ie_domain_param_set domain;
} __attribute__ ((packed));
/** domain regulatory information */
@ -57,7 +58,7 @@ struct lbs_802_11d_domain_reg {
u8 countrycode[COUNTRY_CODE_LEN];
/** No. of 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 {

View file

@ -12,15 +12,14 @@
#include "scan.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))) =
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static const u8 bssid_off[ETH_ALEN] __attribute__ ((aligned (2))) =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
/* The firmware needs certain bits masked out of the beacon-derviced capability
* field when associating/joining to BSSs.
/* The firmware needs the following bits masked out of the beacon-derived
* capability field when associating/joining to a BSS:
* 9 (QoS), 11 (APSD), 12 (unused), 14 (unused), 15 (unused)
*/
#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
*
@ -110,7 +398,7 @@ static void lbs_set_basic_rate_flags(u8 *rates, size_t len)
*
* @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)
{
int ret;
@ -118,11 +406,15 @@ static int lbs_associate(struct lbs_private *priv,
lbs_deb_enter(LBS_DEB_ASSOC);
ret = lbs_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
0, CMD_OPTION_WAITFORRSP,
0, assoc_req->bss.bssid);
if (ret)
goto out;
/* FW v9 and higher indicate authentication suites as a TLV in the
* association command, not as a separate authentication command.
*/
if (priv->fwrelease < 0x09000000) {
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 */
if ((priv->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
@ -133,14 +425,78 @@ static int lbs_associate(struct lbs_private *priv,
if (ret)
goto out;
ret = lbs_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
ret = lbs_associate(priv, assoc_req, CMD_802_11_ASSOCIATE);
out:
lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", 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
*
@ -219,11 +575,10 @@ static int lbs_adhoc_join(struct lbs_private *priv,
memcpy(&cmd.bss.bssid, &bss->bssid, ETH_ALEN);
memcpy(&cmd.bss.ssid, &bss->ssid, bss->ssid_len);
memcpy(&cmd.bss.phyparamset, &bss->phyparamset,
sizeof(union ieeetypes_phyparamset));
memcpy(&cmd.bss.ds, &bss->phy.ds, sizeof(struct ieee_ie_ds_param_set));
memcpy(&cmd.bss.ssparamset, &bss->ssparamset,
sizeof(union IEEEtypes_ssparamset));
memcpy(&cmd.bss.ibss, &bss->ss.ibss,
sizeof(struct ieee_ie_ibss_param_set));
cmd.bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
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);
cmd.bss.ssparamset.ibssparamset.atimwindow = cpu_to_le16(bss->atimwindow);
cmd.bss.ibss.atimwindow = bss->atimwindow;
if (assoc_req->secinfo.wep_enabled) {
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);
if (ret == 0)
ret = lbs_adhoc_post(priv, (struct cmd_header *) &cmd);
if (ret == 0) {
ret = lbs_adhoc_post(priv,
(struct cmd_ds_802_11_ad_hoc_result *)&cmd);
}
out:
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);
/* set Physical parameter set */
cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS;
cmd.phyparamset.dsparamset.len = 1;
cmd.phyparamset.dsparamset.currentchan = assoc_req->channel;
cmd.ds.header.id = WLAN_EID_DS_PARAMS;
cmd.ds.header.len = 1;
cmd.ds.channel = assoc_req->channel;
/* set IBSS parameter set */
cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS;
cmd.ssparamset.ibssparamset.len = 2;
cmd.ssparamset.ibssparamset.atimwindow = 0;
cmd.ibss.header.id = WLAN_EID_IBSS_PARAMS;
cmd.ibss.header.len = 2;
cmd.ibss.atimwindow = cpu_to_le16(0);
/* set capability info */
tmpcap = WLAN_CAPABILITY_IBSS;
if (assoc_req->secinfo.wep_enabled) {
lbs_deb_join("ADHOC_START: WEP enabled, setting privacy on\n");
if (assoc_req->secinfo.wep_enabled ||
assoc_req->secinfo.WPAenabled ||
assoc_req->secinfo.WPA2enabled) {
lbs_deb_join("ADHOC_START: WEP/WPA enabled, privacy on\n");
tmpcap |= WLAN_CAPABILITY_PRIVACY;
} 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);
@ -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);
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:
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);
if (bss != NULL) {
memcpy(&assoc_req->bss, bss, sizeof(struct bss_descriptor));
ret = lbs_associate(priv, assoc_req);
ret = lbs_try_associate(priv, assoc_req);
} else {
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));
if (assoc_req->mode == IW_MODE_INFRA) {
ret = lbs_associate(priv, assoc_req);
lbs_deb_assoc("ASSOC: lbs_associate(bssid) returned %d\n", ret);
ret = lbs_try_associate(priv, assoc_req);
lbs_deb_assoc("ASSOC: lbs_try_associate(bssid) returned %d\n",
ret);
} else if (assoc_req->mode == IW_MODE_ADHOC) {
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
*
@ -1550,285 +1860,3 @@ int lbs_cmd_80211_deauthenticate(struct lbs_private *priv, u8 bssid[ETH_ALEN],
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;
}

View file

@ -8,22 +8,9 @@
void lbs_association_worker(struct work_struct *work);
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_cmd_80211_deauthenticate(struct lbs_private *priv,
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 */

View file

@ -1220,8 +1220,7 @@ static void lbs_submit_command(struct lbs_private *priv,
command = le16_to_cpu(cmd->command);
/* These commands take longer */
if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE ||
command == CMD_802_11_AUTHENTICATE)
if (command == CMD_802_11_SCAN || command == CMD_802_11_ASSOCIATE)
timeo = 5 * HZ;
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);
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_BBP_REG_ACCESS:
case CMD_RF_REG_ACCESS:
@ -1470,8 +1460,8 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
break;
case CMD_802_11_LED_GPIO_CTRL:
{
struct mrvlietypes_ledgpio *gpio =
(struct mrvlietypes_ledgpio*)
struct mrvl_ie_ledgpio *gpio =
(struct mrvl_ie_ledgpio*)
cmdptr->params.ledgpio.data;
memmove(&cmdptr->params.ledgpio,

View file

@ -5,7 +5,7 @@
#include <linux/delay.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <asm/unaligned.h>
#include <net/iw_handler.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);
/* store the non average value */
priv->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
priv->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
priv->SNR[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->SNR);
priv->NF[TYPE_BEACON][TYPE_NOAVG] = get_unaligned_le16(&rssirsp->noisefloor);
priv->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
priv->NF[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgnoisefloor);
priv->SNR[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgSNR);
priv->NF[TYPE_BEACON][TYPE_AVG] = get_unaligned_le16(&rssirsp->avgnoisefloor);
priv->RSSI[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);
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_GET_AFC):
spin_lock_irqsave(&priv->driver_lock, flags);
@ -225,7 +219,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
break;
case CMD_RET(CMD_802_11_AUTHENTICATE):
case CMD_RET(CMD_802_11_BEACON_STOP):
break;

View file

@ -183,12 +183,12 @@ out_unlock:
*/
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;
ssize_t pos = 0;
while (pos < size) {
tlv_h = (struct mrvlietypesheader *) tlv;
tlv_h = (struct mrvl_ie_header *) tlv;
if (!tlv_h->len)
return NULL;
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)
{
struct cmd_ds_802_11_subscribe_event *subscribed;
struct mrvlietypes_thresholds *got;
struct mrvl_ie_thresholds *got;
struct lbs_private *priv = file->private_data;
ssize_t ret = 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)
{
struct cmd_ds_802_11_subscribe_event *events;
struct mrvlietypes_thresholds *tlv;
struct mrvl_ie_thresholds *tlv;
struct lbs_private *priv = file->private_data;
ssize_t buf_size;
int value, freq, new_mask;

View file

@ -321,8 +321,6 @@ struct lbs_private {
u32 monitormode;
u8 fw_ready;
u8 fn_init_required;
u8 fn_shutdown_required;
};
extern struct cmd_confirm_sleep confirm_sleep;
@ -340,7 +338,7 @@ struct bss_descriptor {
u32 rssi;
u32 channel;
u16 beaconperiod;
u32 atimwindow;
__le16 atimwindow;
/* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
u8 mode;
@ -350,10 +348,10 @@ struct bss_descriptor {
unsigned long last_scanned;
union ieeetypes_phyparamset phyparamset;
union IEEEtypes_ssparamset ssparamset;
union ieee_phy_param_set phy;
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];
size_t wpa_ie_len;

View file

@ -250,7 +250,9 @@ struct cmd_ds_gspi_bus_config {
} __attribute__ ((packed));
struct cmd_ds_802_11_authenticate {
u8 macaddr[ETH_ALEN];
struct cmd_header hdr;
u8 bssid[ETH_ALEN];
u8 authtype;
u8 reserved[10];
} __attribute__ ((packed));
@ -263,22 +265,23 @@ struct cmd_ds_802_11_deauthenticate {
} __attribute__ ((packed));
struct cmd_ds_802_11_associate {
u8 peerstaaddr[6];
struct cmd_header hdr;
u8 bssid[6];
__le16 capability;
__le16 listeninterval;
__le16 bcnperiod;
u8 dtimperiod;
#if 0
mrvlietypes_ssidparamset_t ssidParamSet;
mrvlietypes_phyparamset_t phyparamset;
mrvlietypes_ssparamset_t ssparamset;
mrvlietypes_ratesparamset_t ratesParamSet;
#endif
u8 iebuf[512]; /* Enough for required and most optional IEs */
} __attribute__ ((packed));
struct cmd_ds_802_11_associate_rsp {
struct ieeetypes_assocrsp assocRsp;
struct cmd_ds_802_11_associate_response {
struct cmd_header hdr;
__le16 capability;
__le16 statuscode;
__le16 aid;
u8 iebuf[512];
} __attribute__ ((packed));
struct cmd_ds_802_11_set_wep {
@ -535,9 +538,11 @@ struct cmd_ds_802_11_ad_hoc_start {
u8 bsstype;
__le16 beaconperiod;
u8 dtimperiod; /* Reserved on v9 and later */
union IEEEtypes_ssparamset ssparamset;
union ieeetypes_phyparamset phyparamset;
__le16 probedelay;
struct ieee_ie_ibss_param_set ibss;
u8 reserved1[4];
struct ieee_ie_ds_param_set ds;
u8 reserved2[4];
__le16 probedelay; /* Reserved on v9 and later */
__le16 capability;
u8 rates[MAX_RATES];
u8 tlv_memory_size_pad[100];
@ -558,8 +563,10 @@ struct adhoc_bssdesc {
u8 dtimperiod;
__le64 timestamp;
__le64 localtime;
union ieeetypes_phyparamset phyparamset;
union IEEEtypes_ssparamset ssparamset;
struct ieee_ie_ds_param_set ds;
u8 reserved1[4];
struct ieee_ie_ibss_param_set ibss;
u8 reserved2[4];
__le16 capability;
u8 rates[MAX_RATES];
@ -765,8 +772,6 @@ struct cmd_ds_command {
/* command Body */
union {
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_3_get_stat gstat_8023;
struct cmd_ds_802_11_rf_antenna rant;

View file

@ -39,8 +39,24 @@
#include "decl.h"
#include "defs.h"
#include "dev.h"
#include "cmd.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;
module_param_named(helper_name, lbs_helper_name, charp, 0644);
@ -61,7 +77,6 @@ struct if_sdio_model {
int model;
const char *helper;
const char *firmware;
struct if_sdio_card *card;
};
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,
.helper = "sd8385_helper.bin",
.firmware = "sd8385.bin",
.card = NULL,
},
{
/* 8686 */
.model = IF_SDIO_MODEL_8686,
.helper = "sd8686_helper.bin",
.firmware = "sd8686.bin",
.card = NULL,
},
{
/* 8688 */
.model = IF_SDIO_MODEL_8688,
.helper = "sd8688_helper.bin",
.firmware = "sd8688.bin",
.card = NULL,
},
};
@ -927,8 +939,6 @@ static int if_sdio_probe(struct sdio_func *func,
goto free;
}
if_sdio_models[i].card = card;
card->helper = if_sdio_models[i].helper;
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
*/
priv->fn_init_required =
(card->model == IF_SDIO_MODEL_8688) ? 1 : 0;
if (card->model == IF_SDIO_MODEL_8688) {
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);
if (ret)
@ -1057,30 +1075,39 @@ static void if_sdio_remove(struct sdio_func *func)
{
struct if_sdio_card *card;
struct if_sdio_packet *packet;
int ret;
lbs_deb_enter(LBS_DEB_SDIO);
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;
lbs_deb_sdio("call remove card\n");
lbs_stop_card(card->priv);
lbs_remove_card(card->priv);
flush_workqueue(card->workqueue);
destroy_workqueue(card->workqueue);
sdio_claim_host(func);
/* Disable interrupts */
sdio_writeb(func, 0x00, IF_SDIO_H_INT_MASK, &ret);
sdio_release_irq(func);
sdio_disable_func(func);
sdio_release_host(func);
while (card->packets) {
@ -1116,6 +1143,9 @@ static int __init if_sdio_init_module(void)
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);
return ret;
@ -1123,22 +1153,10 @@ static int __init if_sdio_init_module(void)
static void __exit if_sdio_exit_module(void)
{
int i;
struct if_sdio_card *card;
lbs_deb_enter(LBS_DEB_SDIO);
for (i = 0; i < ARRAY_SIZE(if_sdio_models); i++) {
card = if_sdio_models[i].card;
/*
* 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;
}
/* Set the flag as user is removing this module. */
user_rmmod = 1;
sdio_unregister_driver(&if_sdio_driver);

View file

@ -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
* 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)
@ -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)
{
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
* 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)
{
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)
{
/* 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));
buff = cpu_to_le16(val);
return spu_write(card, reg, (u8 *)&buff, sizeof(u16));
}
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;
int err = 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
* don't care about the last one. */
@ -236,18 +227,25 @@ out:
/* Read 16 bits from an SPI register */
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.
* The low 16 bits are read first. */
static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
{
u16 buf[2];
u32 buf;
int err;
err = spu_read(card, reg, (u8 *)buf, sizeof(u32));
err = spu_read(card, reg, (u8 *)&buf, sizeof(buf));
if (!err)
*val = buf[0] | (buf[1] << 16);
*val = le32_to_cpup(&buf);
return err;
}

View file

@ -1002,17 +1002,9 @@ static int lbs_setup_firmware(struct lbs_private *priv)
{
int ret = -1;
s16 curlevel = 0, minlevel = 0, maxlevel = 0;
struct cmd_header cmd;
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 */
memset(priv->current_addr, 0xff, ETH_ALEN);
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->infra_open = 0;
priv->fn_init_required = 0;
priv->fn_shutdown_required = 0;
/* Setup the OS Interface to our functions */
dev->netdev_ops = &lbs_netdev_ops;
dev->watchdog_timeo = 5 * HZ;
@ -1384,20 +1373,11 @@ void lbs_stop_card(struct lbs_private *priv)
struct net_device *dev;
struct cmd_ctrl_node *cmdnode;
unsigned long flags;
struct cmd_header cmd;
lbs_deb_enter(LBS_DEB_MAIN);
if (!priv)
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;
netif_stop_queue(dev);

View file

@ -27,12 +27,12 @@
+ 40) /* 40 for WPAIE */
//! 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 \
* sizeof(struct chanscanparamset)))
//! 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
#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)
{
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.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)
{
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);
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)
{
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);
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,
uint8_t **pbeaconinfo, int *bytesleft)
{
struct ieeetypes_fhparamset *pFH;
struct ieeetypes_dsparamset *pDS;
struct ieeetypes_cfparamset *pCF;
struct ieeetypes_ibssparamset *pibss;
struct ieee_ie_fh_param_set *fh;
struct ieee_ie_ds_param_set *ds;
struct ieee_ie_cf_param_set *cf;
struct ieee_ie_ibss_param_set *ibss;
DECLARE_SSID_BUF(ssid);
struct ieeetypes_countryinfoset *pcountryinfo;
struct ieee_ie_country_info_set *pcountryinfo;
uint8_t *pos, *end, *p;
uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
uint16_t beaconsize = 0;
@ -616,50 +616,49 @@ static int lbs_process_bss(struct bss_descriptor *bss,
break;
case WLAN_EID_FH_PARAMS:
pFH = (struct ieeetypes_fhparamset *) pos;
memmove(&bss->phyparamset.fhparamset, pFH,
sizeof(struct ieeetypes_fhparamset));
fh = (struct ieee_ie_fh_param_set *) pos;
memcpy(&bss->phy.fh, fh, sizeof(*fh));
lbs_deb_scan("got FH IE\n");
break;
case WLAN_EID_DS_PARAMS:
pDS = (struct ieeetypes_dsparamset *) pos;
bss->channel = pDS->currentchan;
memcpy(&bss->phyparamset.dsparamset, pDS,
sizeof(struct ieeetypes_dsparamset));
ds = (struct ieee_ie_ds_param_set *) pos;
bss->channel = ds->channel;
memcpy(&bss->phy.ds, ds, sizeof(*ds));
lbs_deb_scan("got DS IE, channel %d\n", bss->channel);
break;
case WLAN_EID_CF_PARAMS:
pCF = (struct ieeetypes_cfparamset *) pos;
memcpy(&bss->ssparamset.cfparamset, pCF,
sizeof(struct ieeetypes_cfparamset));
cf = (struct ieee_ie_cf_param_set *) pos;
memcpy(&bss->ss.cf, cf, sizeof(*cf));
lbs_deb_scan("got CF IE\n");
break;
case WLAN_EID_IBSS_PARAMS:
pibss = (struct ieeetypes_ibssparamset *) pos;
bss->atimwindow = le16_to_cpu(pibss->atimwindow);
memmove(&bss->ssparamset.ibssparamset, pibss,
sizeof(struct ieeetypes_ibssparamset));
ibss = (struct ieee_ie_ibss_param_set *) pos;
bss->atimwindow = ibss->atimwindow;
memcpy(&bss->ss.ibss, ibss, sizeof(*ibss));
lbs_deb_scan("got IBSS IE\n");
break;
case WLAN_EID_COUNTRY:
pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
pcountryinfo = (struct ieee_ie_country_info_set *) pos;
lbs_deb_scan("got COUNTRY IE\n");
if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
|| pcountryinfo->len > 254) {
lbs_deb_scan("process_bss: 11D- Err CountryInfo len %d, min %zd, max 254\n",
pcountryinfo->len, sizeof(pcountryinfo->countrycode));
if (pcountryinfo->header.len < sizeof(pcountryinfo->countrycode)
|| pcountryinfo->header.len > 254) {
lbs_deb_scan("%s: 11D- Err CountryInfo len %d, min %zd, max 254\n",
__func__,
pcountryinfo->header.len,
sizeof(pcountryinfo->countrycode));
ret = -1;
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",
(uint8_t *) pcountryinfo,
(int) (pcountryinfo->len + 2));
(int) (pcountryinfo->header.len + 2));
break;
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;
}
bytesleft = le16_to_cpu(scanresp->bssdescriptsize);
bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize);
lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
scanrespsize = le16_to_cpu(resp->size);

View file

@ -8,9 +8,14 @@
#include <asm/byteorder.h>
#include <linux/wireless.h>
struct ieeetypes_cfparamset {
u8 elementid;
struct ieee_ie_header {
u8 id;
u8 len;
} __attribute__ ((packed));
struct ieee_ie_cf_param_set {
struct ieee_ie_header header;
u8 cfpcnt;
u8 cfpperiod;
__le16 cfpmaxduration;
@ -18,42 +23,35 @@ struct ieeetypes_cfparamset {
} __attribute__ ((packed));
struct ieeetypes_ibssparamset {
u8 elementid;
u8 len;
struct ieee_ie_ibss_param_set {
struct ieee_ie_header header;
__le16 atimwindow;
} __attribute__ ((packed));
union IEEEtypes_ssparamset {
struct ieeetypes_cfparamset cfparamset;
struct ieeetypes_ibssparamset ibssparamset;
union ieee_ss_param_set {
struct ieee_ie_cf_param_set cf;
struct ieee_ie_ibss_param_set ibss;
} __attribute__ ((packed));
struct ieeetypes_fhparamset {
u8 elementid;
u8 len;
struct ieee_ie_fh_param_set {
struct ieee_ie_header header;
__le16 dwelltime;
u8 hopset;
u8 hoppattern;
u8 hopindex;
} __attribute__ ((packed));
struct ieeetypes_dsparamset {
u8 elementid;
u8 len;
u8 currentchan;
struct ieee_ie_ds_param_set {
struct ieee_ie_header header;
u8 channel;
} __attribute__ ((packed));
union ieeetypes_phyparamset {
struct ieeetypes_fhparamset fhparamset;
struct ieeetypes_dsparamset dsparamset;
} __attribute__ ((packed));
struct ieeetypes_assocrsp {
__le16 capability;
__le16 statuscode;
__le16 aid;
u8 iebuffer[1];
union ieee_phy_param_set {
struct ieee_ie_fh_param_set fh;
struct ieee_ie_ds_param_set ds;
} __attribute__ ((packed));
/** TLV type ID definition */
@ -94,32 +92,33 @@ struct ieeetypes_assocrsp {
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
#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_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291)
/** TLV related data structures*/
struct mrvlietypesheader {
struct mrvl_ie_header {
__le16 type;
__le16 len;
} __attribute__ ((packed));
struct mrvlietypes_data {
struct mrvlietypesheader header;
struct mrvl_ie_data {
struct mrvl_ie_header header;
u8 Data[1];
} __attribute__ ((packed));
struct mrvlietypes_ratesparamset {
struct mrvlietypesheader header;
struct mrvl_ie_rates_param_set {
struct mrvl_ie_header header;
u8 rates[1];
} __attribute__ ((packed));
struct mrvlietypes_ssidparamset {
struct mrvlietypesheader header;
struct mrvl_ie_ssid_param_set {
struct mrvl_ie_header header;
u8 ssid[1];
} __attribute__ ((packed));
struct mrvlietypes_wildcardssidparamset {
struct mrvlietypesheader header;
struct mrvl_ie_wildcard_ssid_param_set {
struct mrvl_ie_header header;
u8 MaxSsidlength;
u8 ssid[1];
} __attribute__ ((packed));
@ -144,91 +143,72 @@ struct chanscanparamset {
__le16 maxscantime;
} __attribute__ ((packed));
struct mrvlietypes_chanlistparamset {
struct mrvlietypesheader header;
struct mrvl_ie_chanlist_param_set {
struct mrvl_ie_header header;
struct chanscanparamset chanscanparam[1];
} __attribute__ ((packed));
struct cfparamset {
struct mrvl_ie_cf_param_set {
struct mrvl_ie_header header;
u8 cfpcnt;
u8 cfpperiod;
__le16 cfpmaxduration;
__le16 cfpdurationremaining;
} __attribute__ ((packed));
struct ibssparamset {
__le16 atimwindow;
struct mrvl_ie_ds_param_set {
struct mrvl_ie_header header;
u8 channel;
} __attribute__ ((packed));
struct mrvlietypes_ssparamset {
struct mrvlietypesheader 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;
struct mrvl_ie_rsn_param_set {
struct mrvl_ie_header header;
u8 rsnie[1];
} __attribute__ ((packed));
struct mrvlietypes_tsftimestamp {
struct mrvlietypesheader header;
struct mrvl_ie_tsf_timestamp {
struct mrvl_ie_header header;
__le64 tsftable[1];
} __attribute__ ((packed));
/* v9 and later firmware only */
struct mrvl_ie_auth_type {
struct mrvl_ie_header header;
__le16 auth;
} __attribute__ ((packed));
/** Local Power capability */
struct mrvlietypes_powercapability {
struct mrvlietypesheader header;
struct mrvl_ie_power_capability {
struct mrvl_ie_header header;
s8 minpower;
s8 maxpower;
} __attribute__ ((packed));
/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
struct mrvlietypes_thresholds {
struct mrvlietypesheader header;
struct mrvl_ie_thresholds {
struct mrvl_ie_header header;
u8 value;
u8 freq;
} __attribute__ ((packed));
struct mrvlietypes_beaconsmissed {
struct mrvlietypesheader header;
struct mrvl_ie_beacons_missed {
struct mrvl_ie_header header;
u8 beaconmissed;
u8 reserved;
} __attribute__ ((packed));
struct mrvlietypes_numprobes {
struct mrvlietypesheader header;
struct mrvl_ie_num_probes {
struct mrvl_ie_header header;
__le16 numprobes;
} __attribute__ ((packed));
struct mrvlietypes_bcastprobe {
struct mrvlietypesheader header;
struct mrvl_ie_bcast_probe {
struct mrvl_ie_header header;
__le16 bcastprobe;
} __attribute__ ((packed));
struct mrvlietypes_numssidprobe {
struct mrvlietypesheader header;
struct mrvl_ie_num_ssid_probe {
struct mrvl_ie_header header;
__le16 numssidprobe;
} __attribute__ ((packed));
@ -237,8 +217,8 @@ struct led_pin {
u8 pin;
} __attribute__ ((packed));
struct mrvlietypes_ledgpio {
struct mrvlietypesheader header;
struct mrvl_ie_ledgpio {
struct mrvl_ie_header header;
struct led_pin ledpin[1];
} __attribute__ ((packed));
@ -250,8 +230,8 @@ struct led_bhv {
} __attribute__ ((packed));
struct mrvlietypes_ledbhv {
struct mrvlietypesheader header;
struct mrvl_ie_ledbhv {
struct mrvl_ie_header header;
struct led_bhv ledbhv[1];
} __attribute__ ((packed));

View file

@ -280,7 +280,6 @@ struct mac80211_hwsim_data {
struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
struct ieee80211_channel *channel;
int radio_enabled;
unsigned long beacon_int; /* in jiffies unit */
unsigned int rx_filter;
int started;
@ -418,8 +417,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
if (data == data2)
continue;
if (!data2->started || !data2->radio_enabled ||
!hwsim_ps_rx_ok(data2, skb) ||
if (!data2->started || !hwsim_ps_rx_ok(data2, skb) ||
data->channel->center_freq != data2->channel->center_freq ||
!(data->group & data2->group))
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)
{
struct mac80211_hwsim_data *data = hw->priv;
bool ack;
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;
}
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);
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 mac80211_hwsim_data *data = hw->priv;
if (!data->started || !data->radio_enabled)
if (!data->started)
return;
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 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__,
conf->channel->center_freq, conf->radio_enabled,
conf->channel->center_freq,
!!(conf->flags & IEEE80211_CONF_IDLE),
!!(conf->flags & IEEE80211_CONF_PS));
data->channel = conf->channel;
data->radio_enabled = conf->radio_enabled;
if (!data->started || !data->radio_enabled || !data->beacon_int)
if (!data->started || !data->beacon_int)
del_timer(&data->beacon_timer);
else
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);
memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
memcpy(pspoll->ta, mac, ETH_ALEN);
if (data->radio_enabled &&
!mac80211_hwsim_tx_frame(data->hw, skb))
if (!mac80211_hwsim_tx_frame(data->hw, skb))
printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__);
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->addr2, mac, ETH_ALEN);
memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
if (data->radio_enabled &&
!mac80211_hwsim_tx_frame(data->hw, skb))
if (!mac80211_hwsim_tx_frame(data->hw, skb))
printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
dev_kfree_skb(skb);
}

View file

@ -84,8 +84,8 @@ MODULE_DEVICE_TABLE(usb, p54u_table);
static const struct {
u32 intf;
enum p54u_hw_type type;
char fw[FIRMWARE_NAME_MAX];
char fw_legacy[FIRMWARE_NAME_MAX];
const char *fw;
const char *fw_legacy;
char hw[20];
} p54u_fwlist[__NUM_P54U_HWTYPES] = {
{

View file

@ -520,7 +520,7 @@ static void rt2400pci_config_ps(struct rt2x00_dev *rt2x00dev,
if (state == STATE_SLEEP) {
rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
rt2x00_set_field32(&reg, CSR20_DELAY_AFTER_TBCN,
(libconf->conf->beacon_int - 20) * 16);
(rt2x00dev->beacon_int - 20) * 16);
rt2x00_set_field32(&reg, CSR20_TBCN_BEFORE_WAKEUP,
libconf->conf->listen_interval - 1);

View file

@ -569,7 +569,7 @@ static void rt2500pci_config_ps(struct rt2x00_dev *rt2x00dev,
if (state == STATE_SLEEP) {
rt2x00pci_register_read(rt2x00dev, CSR20, &reg);
rt2x00_set_field32(&reg, CSR20_DELAY_AFTER_TBCN,
(libconf->conf->beacon_int - 20) * 16);
(rt2x00dev->beacon_int - 20) * 16);
rt2x00_set_field32(&reg, CSR20_TBCN_BEFORE_WAKEUP,
libconf->conf->listen_interval - 1);

View file

@ -647,7 +647,7 @@ static void rt2500usb_config_ps(struct rt2x00_dev *rt2x00dev,
if (state == STATE_SLEEP) {
rt2500usb_register_read(rt2x00dev, MAC_CSR18, &reg);
rt2x00_set_field16(&reg, MAC_CSR18_DELAY_AFTER_BEACON,
libconf->conf->beacon_int - 20);
rt2x00dev->beacon_int - 20);
rt2x00_set_field16(&reg, MAC_CSR18_BEACONS_BEFORE_WAKEUP,
libconf->conf->listen_interval - 1);

View file

@ -2927,12 +2927,17 @@ static struct usb_device_id rt2800usb_device_table[] = {
{ USB_DEVICE(0x07d1, 0x3c09), 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, 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, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Edimax */
{ USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x7392, 0x7717), 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 */
{ USB_DEVICE(0X1740, 0x9701), 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, 0x0009), 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 */
{ USB_DEVICE(0x1740, 0x0605), 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 */
{ USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Philips */
{ USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Planex */
@ -2981,6 +2989,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
/* Quanta */
{ USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
/* Ralink */
{ USB_DEVICE(0x0db0, 0x3820), 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, 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, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
/* SMC */
{ USB_DEVICE(0x083a, 0x6618), 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 */
{ USB_DEVICE(0x5a57, 0x0280), 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 */
{ USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
{ USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) },

View file

@ -801,6 +801,11 @@ struct rt2x00_dev {
*/
u8 calibration[2];
/*
* Beacon interval.
*/
u16 beacon_int;
/*
* Low level statistics which will have
* to be kept up to date while device is running.

View file

@ -108,6 +108,9 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
erp.basic_rates = bss_conf->basic_rates;
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);
}

View file

@ -956,7 +956,7 @@ static void rt61pci_config_ps(struct rt2x00_dev *rt2x00dev,
if (state == STATE_SLEEP) {
rt2x00pci_register_read(rt2x00dev, MAC_CSR11, &reg);
rt2x00_set_field32(&reg, MAC_CSR11_DELAY_AFTER_TBCN,
libconf->conf->beacon_int - 10);
rt2x00dev->beacon_int - 10);
rt2x00_set_field32(&reg, MAC_CSR11_TBCN_BEFORE_WAKEUP,
libconf->conf->listen_interval - 1);
rt2x00_set_field32(&reg, MAC_CSR11_WAKEUP_LATENCY, 5);

View file

@ -852,7 +852,7 @@ static void rt73usb_config_ps(struct rt2x00_dev *rt2x00dev,
if (state == STATE_SLEEP) {
rt2x00usb_register_read(rt2x00dev, MAC_CSR11, &reg);
rt2x00_set_field32(&reg, MAC_CSR11_DELAY_AFTER_TBCN,
libconf->conf->beacon_int - 10);
rt2x00dev->beacon_int - 10);
rt2x00_set_field32(&reg, MAC_CSR11_TBCN_BEFORE_WAKEUP,
libconf->conf->listen_interval - 1);
rt2x00_set_field32(&reg, MAC_CSR11_WAKEUP_LATENCY, 5);

View file

@ -21,7 +21,7 @@ config ACER_WMI
depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
depends on RFKILL
depends on RFKILL || RFKILL = n
select ACPI_WMI
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
@ -60,7 +60,7 @@ config DELL_LAPTOP
depends on DCDBAS
depends on EXPERIMENTAL
depends on BACKLIGHT_CLASS_DEVICE
depends on RFKILL
depends on RFKILL || RFKILL = n
depends on POWER_SUPPLY
default n
---help---
@ -117,7 +117,7 @@ config HP_WMI
tristate "HP WMI extras"
depends on ACPI_WMI
depends on INPUT
depends on RFKILL
depends on RFKILL || RFKILL = n
help
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.
@ -196,14 +196,13 @@ config THINKPAD_ACPI
tristate "ThinkPad ACPI Laptop Extras"
depends on ACPI
depends on INPUT
depends on RFKILL || RFKILL = n
select BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE
select HWMON
select NVRAM
select NEW_LEDS
select LEDS_CLASS
select NET
select RFKILL
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
@ -338,9 +337,9 @@ config EEEPC_LAPTOP
depends on ACPI
depends on INPUT
depends on EXPERIMENTAL
depends on RFKILL || RFKILL = n
select BACKLIGHT_CLASS_DEVICE
select HWMON
select RFKILL
---help---
This driver supports the Fn-Fx keys on Eee PC laptops.
It also adds the ability to switch camera/wlan on/off.
@ -405,9 +404,8 @@ config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on ACPI
depends on INPUT
depends on RFKILL || RFKILL = n
select INPUT_POLLDEV
select NET
select RFKILL
select BACKLIGHT_CLASS_DEVICE
---help---
This driver adds support for access to certain system settings

View file

@ -958,58 +958,50 @@ static void acer_rfkill_update(struct work_struct *ignored)
status = get_u32(&state, ACER_CAP_WIRELESS);
if (ACPI_SUCCESS(status))
rfkill_force_state(wireless_rfkill, state ?
RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
rfkill_set_sw_state(wireless_rfkill, !!state);
if (has_cap(ACER_CAP_BLUETOOTH)) {
status = get_u32(&state, ACER_CAP_BLUETOOTH);
if (ACPI_SUCCESS(status))
rfkill_force_state(bluetooth_rfkill, state ?
RFKILL_STATE_UNBLOCKED :
RFKILL_STATE_SOFT_BLOCKED);
rfkill_set_sw_state(bluetooth_rfkill, !!state);
}
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;
u32 *cap = data;
status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
u32 cap = (unsigned long)data;
status = set_u32(!!blocked, cap);
if (ACPI_FAILURE(status))
return -ENODEV;
return 0;
}
static struct rfkill * acer_rfkill_register(struct device *dev,
enum rfkill_type type, char *name, u32 cap)
static const struct rfkill_ops acer_rfkill_ops = {
.set_block = acer_rfkill_set,
};
static struct rfkill *acer_rfkill_register(struct device *dev,
enum rfkill_type type,
char *name, u32 cap)
{
int err;
u32 state;
u32 *data;
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)
return ERR_PTR(-ENOMEM);
rfkill_dev->name = name;
get_u32(&state, cap);
rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
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;
rfkill_set_sw_state(rfkill_dev, !state);
err = rfkill_register(rfkill_dev);
if (err) {
kfree(rfkill_dev->data);
rfkill_free(rfkill_dev);
rfkill_destroy(rfkill_dev);
return ERR_PTR(err);
}
return rfkill_dev;
@ -1027,8 +1019,8 @@ static int acer_rfkill_init(struct device *dev)
RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
ACER_CAP_BLUETOOTH);
if (IS_ERR(bluetooth_rfkill)) {
kfree(wireless_rfkill->data);
rfkill_unregister(wireless_rfkill);
rfkill_destroy(wireless_rfkill);
return PTR_ERR(bluetooth_rfkill);
}
}
@ -1041,11 +1033,13 @@ static int acer_rfkill_init(struct device *dev)
static void acer_rfkill_exit(void)
{
cancel_delayed_work_sync(&acer_rfkill_work);
kfree(wireless_rfkill->data);
rfkill_unregister(wireless_rfkill);
rfkill_destroy(wireless_rfkill);
if (has_cap(ACER_CAP_BLUETOOTH)) {
kfree(bluetooth_rfkill->data);
rfkill_unregister(bluetooth_rfkill);
rfkill_destroy(bluetooth_rfkill);
}
return;
}

View file

@ -174,10 +174,11 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
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;
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));
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;
}
static int dell_wifi_set(void *data, enum rfkill_state state)
{
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)
static void dell_rfkill_query(struct rfkill *rfkill, void *data)
{
struct calling_interface_buffer buffer;
int status;
int new_state = RFKILL_STATE_HARD_BLOCKED;
int bit = (unsigned long)data + 16;
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
dell_send_request(&buffer, 17, 11);
status = buffer.output[1];
if (status & (1<<16))
new_state = RFKILL_STATE_SOFT_BLOCKED;
if (status & (1<<bit))
*state = new_state;
else
*state = RFKILL_STATE_UNBLOCKED;
return 0;
if (status & BIT(bit))
rfkill_set_hw_state(rfkill, !!(status & BIT(16)));
}
static int dell_wifi_get(void *data, enum rfkill_state *state)
{
return dell_rfkill_get(17, state);
}
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 const struct rfkill_ops dell_rfkill_ops = {
.set_block = dell_rfkill_set,
.query = dell_rfkill_query,
};
static int dell_setup_rfkill(void)
{
@ -248,36 +217,37 @@ static int dell_setup_rfkill(void)
status = buffer.output[1];
if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN);
if (!wifi_rfkill)
wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN,
&dell_rfkill_ops, (void *) 1);
if (!wifi_rfkill) {
ret = -ENOMEM;
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);
if (ret)
goto err_wifi;
}
if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH);
if (!bluetooth_rfkill)
bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL,
RFKILL_TYPE_BLUETOOTH,
&dell_rfkill_ops, (void *) 2);
if (!bluetooth_rfkill) {
ret = -ENOMEM;
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);
if (ret)
goto err_bluetooth;
}
if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN);
if (!wwan_rfkill)
wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN,
&dell_rfkill_ops, (void *) 3);
if (!wwan_rfkill) {
ret = -ENOMEM;
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);
if (ret)
goto err_wwan;
@ -285,22 +255,15 @@ static int dell_setup_rfkill(void)
return 0;
err_wwan:
if (wwan_rfkill)
rfkill_free(wwan_rfkill);
if (bluetooth_rfkill) {
rfkill_unregister(bluetooth_rfkill);
bluetooth_rfkill = NULL;
}
err_bluetooth:
rfkill_destroy(wwan_rfkill);
if (bluetooth_rfkill)
rfkill_free(bluetooth_rfkill);
if (wifi_rfkill) {
rfkill_unregister(wifi_rfkill);
wifi_rfkill = NULL;
}
err_wifi:
rfkill_unregister(bluetooth_rfkill);
err_bluetooth:
rfkill_destroy(bluetooth_rfkill);
if (wifi_rfkill)
rfkill_free(wifi_rfkill);
rfkill_unregister(wifi_rfkill);
err_wifi:
rfkill_destroy(wifi_rfkill);
return ret;
}

View file

@ -299,39 +299,22 @@ static int update_bl_status(struct backlight_device *bd)
* Rfkill helpers
*/
static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
{
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)
static bool eeepc_wlan_rfkill_blocked(void)
{
if (get_acpi(CM_ASL_WLAN) == 1)
*state = RFKILL_STATE_UNBLOCKED;
else
*state = RFKILL_STATE_SOFT_BLOCKED;
return 0;
return false;
return true;
}
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)
return set_acpi(CM_ASL_BLUETOOTH, 0);
else
return set_acpi(CM_ASL_BLUETOOTH, 1);
unsigned long asl = (unsigned long)data;
return set_acpi(asl, !blocked);
}
static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
{
if (get_acpi(CM_ASL_BLUETOOTH) == 1)
*state = RFKILL_STATE_UNBLOCKED;
else
*state = RFKILL_STATE_SOFT_BLOCKED;
return 0;
}
static const struct rfkill_ops eeepc_rfkill_ops = {
.set_block = eeepc_rfkill_set,
};
/*
* Sys helpers
@ -531,9 +514,9 @@ static int notify_brn(void)
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
{
enum rfkill_state state;
struct pci_dev *dev;
struct pci_bus *bus = pci_find_bus(0, 1);
bool blocked;
if (event != ACPI_NOTIFY_BUS_CHECK)
return;
@ -543,9 +526,8 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
return;
}
eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state);
if (state == RFKILL_STATE_UNBLOCKED) {
blocked = eeepc_wlan_rfkill_blocked();
if (!blocked) {
dev = pci_get_slot(bus, 0);
if (dev) {
/* 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)
@ -684,26 +666,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
if (get_acpi(CM_ASL_WLAN) != -1) {
ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
RFKILL_TYPE_WLAN);
ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
&device->dev,
RFKILL_TYPE_WLAN,
&eeepc_rfkill_ops,
(void *)CM_ASL_WLAN);
if (!ehotk->eeepc_wlan_rfkill)
goto wlan_fail;
ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
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);
}
rfkill_set_global_sw_state(RFKILL_TYPE_WLAN,
get_acpi(CM_ASL_WLAN) != 1);
result = rfkill_register(ehotk->eeepc_wlan_rfkill);
if (result)
goto wlan_fail;
@ -711,28 +684,17 @@ static int eeepc_hotk_add(struct acpi_device *device)
if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
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)
goto bluetooth_fail;
ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
ehotk->eeepc_bluetooth_rfkill->toggle_radio =
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);
}
rfkill_set_global_sw_state(RFKILL_TYPE_BLUETOOTH,
get_acpi(CM_ASL_BLUETOOTH) != 1);
result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
if (result)
goto bluetooth_fail;
@ -741,13 +703,10 @@ static int eeepc_hotk_add(struct acpi_device *device)
return 0;
bluetooth_fail:
if (ehotk->eeepc_bluetooth_rfkill)
rfkill_free(ehotk->eeepc_bluetooth_rfkill);
rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
rfkill_unregister(ehotk->eeepc_wlan_rfkill);
ehotk->eeepc_wlan_rfkill = NULL;
wlan_fail:
if (ehotk->eeepc_wlan_rfkill)
rfkill_free(ehotk->eeepc_wlan_rfkill);
rfkill_destroy(ehotk->eeepc_wlan_rfkill);
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
ehotk_fail:

View file

@ -154,58 +154,46 @@ static int hp_wmi_dock_state(void)
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)
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x101);
else
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x100);
unsigned long b = (unsigned long) data;
int query = BIT(b + 8) | ((!!blocked) << b);
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
}
static int hp_wmi_bluetooth_set(void *data, enum rfkill_state state)
{
if (state)
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x202);
else
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 0x200);
}
static const struct rfkill_ops hp_wmi_rfkill_ops = {
.set_block = hp_wmi_set_block,
};
static int hp_wmi_wwan_set(void *data, enum rfkill_state state)
{
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)
static bool hp_wmi_wifi_state(void)
{
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
if (wireless & 0x100)
return RFKILL_STATE_UNBLOCKED;
return false;
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);
if (wireless & 0x10000)
return RFKILL_STATE_UNBLOCKED;
return false;
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);
if (wireless & 0x1000000)
return RFKILL_STATE_UNBLOCKED;
return false;
else
return RFKILL_STATE_SOFT_BLOCKED;
return true;
}
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) {
if (wifi_rfkill)
rfkill_force_state(wifi_rfkill,
hp_wmi_wifi_state());
rfkill_set_sw_state(wifi_rfkill,
hp_wmi_wifi_state());
if (bluetooth_rfkill)
rfkill_force_state(bluetooth_rfkill,
hp_wmi_bluetooth_state());
rfkill_set_sw_state(bluetooth_rfkill,
hp_wmi_bluetooth_state());
if (wwan_rfkill)
rfkill_force_state(wwan_rfkill,
hp_wmi_wwan_state());
rfkill_set_sw_state(wwan_rfkill,
hp_wmi_wwan_state());
} else
printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
eventcode);
@ -430,31 +418,34 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
goto add_sysfs_error;
if (wireless & 0x1) {
wifi_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WLAN);
wifi_rfkill->name = "hp-wifi";
wifi_rfkill->state = hp_wmi_wifi_state();
wifi_rfkill->toggle_radio = hp_wmi_wifi_set;
wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
RFKILL_TYPE_WLAN,
&hp_wmi_rfkill_ops,
(void *) 0);
rfkill_set_sw_state(wifi_rfkill, hp_wmi_wifi_state());
err = rfkill_register(wifi_rfkill);
if (err)
goto add_sysfs_error;
goto register_wifi_error;
}
if (wireless & 0x2) {
bluetooth_rfkill = rfkill_allocate(&device->dev,
RFKILL_TYPE_BLUETOOTH);
bluetooth_rfkill->name = "hp-bluetooth";
bluetooth_rfkill->state = hp_wmi_bluetooth_state();
bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set;
bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
RFKILL_TYPE_BLUETOOTH,
&hp_wmi_rfkill_ops,
(void *) 1);
rfkill_set_sw_state(bluetooth_rfkill,
hp_wmi_bluetooth_state());
err = rfkill_register(bluetooth_rfkill);
if (err)
goto register_bluetooth_error;
}
if (wireless & 0x4) {
wwan_rfkill = rfkill_allocate(&device->dev, RFKILL_TYPE_WWAN);
wwan_rfkill->name = "hp-wwan";
wwan_rfkill->state = hp_wmi_wwan_state();
wwan_rfkill->toggle_radio = hp_wmi_wwan_set;
wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
RFKILL_TYPE_WWAN,
&hp_wmi_rfkill_ops,
(void *) 2);
rfkill_set_sw_state(wwan_rfkill, hp_wmi_wwan_state());
err = rfkill_register(wwan_rfkill);
if (err)
goto register_wwan_err;
@ -462,11 +453,15 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
return 0;
register_wwan_err:
rfkill_destroy(wwan_rfkill);
if (bluetooth_rfkill)
rfkill_unregister(bluetooth_rfkill);
register_bluetooth_error:
rfkill_destroy(bluetooth_rfkill);
if (wifi_rfkill)
rfkill_unregister(wifi_rfkill);
register_wifi_error:
rfkill_destroy(wifi_rfkill);
add_sysfs_error:
cleanup_sysfs(device);
return err;
@ -476,12 +471,18 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
{
cleanup_sysfs(device);
if (wifi_rfkill)
if (wifi_rfkill) {
rfkill_unregister(wifi_rfkill);
if (bluetooth_rfkill)
rfkill_destroy(wifi_rfkill);
}
if (bluetooth_rfkill) {
rfkill_unregister(bluetooth_rfkill);
if (wwan_rfkill)
rfkill_destroy(wifi_rfkill);
}
if (wwan_rfkill) {
rfkill_unregister(wwan_rfkill);
rfkill_destroy(wwan_rfkill);
}
return 0;
}

View file

@ -128,11 +128,11 @@ enum sony_nc_rfkill {
SONY_BLUETOOTH,
SONY_WWAN,
SONY_WIMAX,
SONY_RFKILL_MAX,
N_SONY_RFKILL,
};
static struct rfkill *sony_rfkill_devices[SONY_RFKILL_MAX];
static int sony_rfkill_address[SONY_RFKILL_MAX] = {0x300, 0x500, 0x700, 0x900};
static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
static void sony_nc_rfkill_update(void);
/*********** Input Devices ***********/
@ -1051,147 +1051,98 @@ static void sony_nc_rfkill_cleanup(void)
{
int i;
for (i = 0; i < SONY_RFKILL_MAX; i++) {
if (sony_rfkill_devices[i])
for (i = 0; i < N_SONY_RFKILL; i++) {
if (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)
{
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)
static int sony_nc_rfkill_set(void *data, bool blocked)
{
int result;
int argument = sony_rfkill_address[(long) data] + 0x100;
if (state == RFKILL_STATE_UNBLOCKED)
if (!blocked)
argument |= 0xff0000;
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;
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);
if (!sony_wifi_rfkill)
return -1;
sony_wifi_rfkill->name = "sony-wifi";
sony_wifi_rfkill->toggle_radio = sony_nc_rfkill_set;
sony_wifi_rfkill->get_state = sony_nc_rfkill_get;
sony_wifi_rfkill->data = (void *)SONY_WIFI;
err = rfkill_register(sony_wifi_rfkill);
if (err)
rfkill_free(sony_wifi_rfkill);
else {
sony_rfkill_devices[SONY_WIFI] = sony_wifi_rfkill;
sony_nc_rfkill_set(sony_wifi_rfkill->data,
RFKILL_STATE_UNBLOCKED);
switch (nc_type) {
case SONY_WIFI:
type = RFKILL_TYPE_WLAN;
name = "sony-wifi";
break;
case SONY_BLUETOOTH:
type = RFKILL_TYPE_BLUETOOTH;
name = "sony-bluetooth";
break;
case SONY_WWAN:
type = RFKILL_TYPE_WWAN;
name = "sony-wwan";
break;
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)
{
int err = 0;
struct rfkill *sony_bluetooth_rfkill;
rfk = rfkill_alloc(name, &device->dev, type,
&sony_rfkill_ops, (void *)nc_type);
if (!rfk)
return -ENOMEM;
sony_bluetooth_rfkill = rfkill_allocate(&device->dev,
RFKILL_TYPE_BLUETOOTH);
if (!sony_bluetooth_rfkill)
return -1;
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);
err = rfkill_register(rfk);
if (err) {
rfkill_destroy(rfk);
return err;
}
sony_rfkill_devices[nc_type] = rfk;
sony_nc_rfkill_set((void *)nc_type, false);
return err;
}
static void sony_nc_rfkill_update()
{
int i;
enum rfkill_state state;
enum sony_nc_rfkill i;
int result;
bool hwblock;
for (i = 0; i < SONY_RFKILL_MAX; i++) {
if (sony_rfkill_devices[i]) {
sony_rfkill_devices[i]->
get_state(sony_rfkill_devices[i]->data,
&state);
rfkill_force_state(sony_rfkill_devices[i], state);
sony_call_snc_handle(0x124, 0x200, &result);
hwblock = !(result & 0x1);
for (i = 0; i < N_SONY_RFKILL; i++) {
int argument = sony_rfkill_address[i];
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)
sony_nc_setup_wifi_rfkill(device);
sony_nc_setup_rfkill(device, SONY_WIFI);
if (result & 0x2)
sony_nc_setup_bluetooth_rfkill(device);
sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
if (result & 0x1c)
sony_nc_setup_wwan_rfkill(device);
sony_nc_setup_rfkill(device, SONY_WWAN);
if (result & 0x20)
sony_nc_setup_wimax_rfkill(device);
sony_nc_setup_rfkill(device, SONY_WIMAX);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -45,7 +45,6 @@
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
#include <linux/input-polldev.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 platform_device *p_dev;
struct rfkill *rfk_dev;
struct input_polled_dev *poll_dev;
struct rfkill *bt_rfk;
const char *bt_name;
const char *rfk_name;
bool last_rfk_state;
struct mutex mutex;
};
static struct toshiba_acpi_dev toshiba_acpi = {
.bt_name = "Toshiba Bluetooth",
.rfk_name = "Toshiba RFKill Switch",
.last_rfk_state = false,
};
/* Bluetooth rfkill handlers */
@ -283,21 +276,6 @@ static u32 hci_get_bt_present(bool *present)
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)
{
u32 hci_result;
@ -311,70 +289,67 @@ static u32 hci_get_radio_state(bool *radio_state)
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 value;
int err;
bool radio_state;
struct toshiba_acpi_dev *dev = data;
value = (state == RFKILL_STATE_UNBLOCKED);
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;
}
value = (blocked == false);
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_ATTACH, &result2);
mutex_unlock(&dev->mutex);
if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
return -EFAULT;
return 0;
err = -EBUSY;
else
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 value;
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);
if (hci_result != HCI_SUCCESS)
return; /* Can't do anything useful */
if (hci_result != HCI_SUCCESS) {
/* Can't do anything useful */
mutex_unlock(&dev->mutex);
}
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);
if (unlikely(state_changed)) {
rfkill_force_state(dev->rfk_dev,
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);
}
if (rfkill_set_hw_state(rfkill, !new_rfk_state))
bt_rfkill_set_block(data, true);
}
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 backlight_device *toshiba_backlight_device;
static int force_fan;
@ -702,14 +677,11 @@ static struct backlight_ops toshiba_backlight_data = {
static void toshiba_acpi_exit(void)
{
if (toshiba_acpi.poll_dev) {
input_unregister_polled_device(toshiba_acpi.poll_dev);
input_free_polled_device(toshiba_acpi.poll_dev);
if (toshiba_acpi.bt_rfk) {
rfkill_unregister(toshiba_acpi.bt_rfk);
rfkill_destroy(toshiba_acpi.bt_rfk);
}
if (toshiba_acpi.rfk_dev)
rfkill_unregister(toshiba_acpi.rfk_dev);
if (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;
u32 hci_result;
bool bt_present;
bool bt_on;
bool radio_on;
int ret = 0;
if (acpi_disabled)
@ -793,60 +763,21 @@ static int __init toshiba_acpi_init(void)
/* Register rfkill switch for Bluetooth */
if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev,
RFKILL_TYPE_BLUETOOTH);
if (!toshiba_acpi.rfk_dev) {
toshiba_acpi.bt_rfk = rfkill_alloc(toshiba_acpi.bt_name,
&toshiba_acpi.p_dev->dev,
RFKILL_TYPE_BLUETOOTH,
&toshiba_rfk_ops,
&toshiba_acpi);
if (!toshiba_acpi.bt_rfk) {
printk(MY_ERR "unable to allocate rfkill device\n");
toshiba_acpi_exit();
return -ENOMEM;
}
toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
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);
ret = rfkill_register(toshiba_acpi.bt_rfk);
if (ret) {
printk(MY_ERR "unable to register rfkill device\n");
toshiba_acpi_exit();
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");
rfkill_destroy(toshiba_acpi.bt_rfk);
toshiba_acpi_exit();
return ret;
}

View file

@ -106,4 +106,6 @@
#define EOWNERDEAD 130 /* Owner died */
#define ENOTRECOVERABLE 131 /* State not recoverable */
#define ERFKILL 132 /* Operation not possible due to RF-kill */
#endif

View file

@ -311,6 +311,7 @@ unifdef-y += ptrace.h
unifdef-y += qnx4_fs.h
unifdef-y += quota.h
unifdef-y += random.h
unifdef-y += rfkill.h
unifdef-y += irqnr.h
unifdef-y += reboot.h
unifdef-y += reiserfs_fs.h

Some files were not shown because too many files have changed in this diff Show more