Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
net
wimax
i2400m
op-rfkill.c
Go to the documentation of this file.
1
/*
2
* Intel Wireless WiMAX Connection 2400m
3
* Implement backend for the WiMAX stack rfkill support
4
*
5
*
6
* Copyright (C) 2007-2008 Intel Corporation <
[email protected]
>
7
* Inaky Perez-Gonzalez <
[email protected]
>
8
*
9
* This program is free software; you can redistribute it and/or
10
* modify it under the terms of the GNU General Public License version
11
* 2 as published by the Free Software Foundation.
12
*
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21
* 02110-1301, USA.
22
*
23
*
24
* The WiMAX kernel stack integrates into RF-Kill and keeps the
25
* switches's status. We just need to:
26
*
27
* - report changes in the HW RF Kill switch [with
28
* wimax_rfkill_{sw,hw}_report(), which happens when we detect those
29
* indications coming through hardware reports]. We also do it on
30
* initialization to let the stack know the initial HW state.
31
*
32
* - implement indications from the stack to change the SW RF Kill
33
* switch (coming from sysfs, the wimax stack or user space).
34
*/
35
#include "
i2400m.h
"
36
#include <
linux/wimax/i2400m.h
>
37
#include <linux/slab.h>
38
39
40
41
#define D_SUBMODULE rfkill
42
#include "
debug-levels.h
"
43
44
/*
45
* Return true if the i2400m radio is in the requested wimax_rf_state state
46
*
47
*/
48
static
49
int
i2400m_radio_is(
struct
i2400m
*
i2400m
,
enum
wimax_rf_state
state
)
50
{
51
if
(state ==
WIMAX_RF_OFF
)
52
return
i2400m->
state
==
I2400M_SS_RF_OFF
53
|| i2400m->
state
==
I2400M_SS_RF_SHUTDOWN
;
54
else
if
(state ==
WIMAX_RF_ON
)
55
/* state == WIMAX_RF_ON */
56
return
i2400m->
state
!=
I2400M_SS_RF_OFF
57
&& i2400m->
state
!=
I2400M_SS_RF_SHUTDOWN
;
58
else
{
59
BUG
();
60
return
-
EINVAL
;
/* shut gcc warnings on certain arches */
61
}
62
}
63
64
65
/*
66
* WiMAX stack operation: implement SW RFKill toggling
67
*
68
* @wimax_dev: device descriptor
69
* @skb: skb where the message has been received; skb->data is
70
* expected to point to the message payload.
71
* @genl_info: passed by the generic netlink layer
72
*
73
* Generic Netlink will call this function when a message is sent from
74
* userspace to change the software RF-Kill switch status.
75
*
76
* This function will set the device's software RF-Kill switch state to
77
* match what is requested.
78
*
79
* NOTE: the i2400m has a strict state machine; we can only set the
80
* RF-Kill switch when it is on, the HW RF-Kill is on and the
81
* device is initialized. So we ignore errors steaming from not
82
* being in the right state (-EILSEQ).
83
*/
84
int
i2400m_op_rfkill_sw_toggle
(
struct
wimax_dev
*
wimax_dev
,
85
enum
wimax_rf_state
state
)
86
{
87
int
result
;
88
struct
i2400m
*
i2400m
= wimax_dev_to_i2400m(wimax_dev);
89
struct
device
*
dev
= i2400m_dev(i2400m);
90
struct
sk_buff
*ack_skb;
91
struct
{
92
struct
i2400m_l3l4_hdr
hdr;
93
struct
i2400m_tlv_rf_operation
sw_rf;
94
}
__packed
*
cmd
;
95
char
strerr[32];
96
97
d_fnstart
(4, dev,
"(wimax_dev %p state %d)\n"
, wimax_dev, state);
98
99
result = -
ENOMEM
;
100
cmd = kzalloc(
sizeof
(*cmd),
GFP_KERNEL
);
101
if
(cmd ==
NULL
)
102
goto
error_alloc;
103
cmd->hdr.
type
=
cpu_to_le16
(
I2400M_MT_CMD_RF_CONTROL
);
104
cmd->hdr.
length
=
sizeof
(cmd->sw_rf);
105
cmd->hdr.
version
=
cpu_to_le16
(
I2400M_L3L4_VERSION
);
106
cmd->sw_rf.hdr.
type
=
cpu_to_le16
(
I2400M_TLV_RF_OPERATION
);
107
cmd->sw_rf.hdr.
length
=
cpu_to_le16
(
sizeof
(cmd->sw_rf.status));
108
switch
(state) {
109
case
WIMAX_RF_OFF
:
/* RFKILL ON, radio OFF */
110
cmd->sw_rf.status =
cpu_to_le32
(2);
111
break
;
112
case
WIMAX_RF_ON
:
/* RFKILL OFF, radio ON */
113
cmd->sw_rf.status =
cpu_to_le32
(1);
114
break
;
115
default
:
116
BUG
();
117
}
118
119
ack_skb =
i2400m_msg_to_dev
(i2400m, cmd,
sizeof
(*cmd));
120
result = PTR_ERR(ack_skb);
121
if
(IS_ERR(ack_skb)) {
122
dev_err
(dev,
"Failed to issue 'RF Control' command: %d\n"
,
123
result);
124
goto
error_msg_to_dev;
125
}
126
result =
i2400m_msg_check_status
(
wimax_msg_data
(ack_skb),
127
strerr,
sizeof
(strerr));
128
if
(result < 0) {
129
dev_err
(dev,
"'RF Control' (0x%04x) command failed: %d - %s\n"
,
130
I2400M_MT_CMD_RF_CONTROL
, result, strerr);
131
goto
error_cmd;
132
}
133
134
/* Now we wait for the state to change to RADIO_OFF or RADIO_ON */
135
result =
wait_event_timeout
(
136
i2400m->
state_wq
, i2400m_radio_is(i2400m, state),
137
5 *
HZ
);
138
if
(result == 0)
139
result = -
ETIMEDOUT
;
140
if
(result < 0)
141
dev_err
(dev,
"Error waiting for device to toggle RF state: "
142
"%d\n"
, result);
143
result = 0;
144
error_cmd:
145
kfree_skb
(ack_skb);
146
error_msg_to_dev:
147
error_alloc:
148
d_fnend
(4, dev,
"(wimax_dev %p state %d) = %d\n"
,
149
wimax_dev, state, result);
150
return
result
;
151
}
152
153
154
/*
155
* Inform the WiMAX stack of changes in the RF Kill switches reported
156
* by the device
157
*
158
* @i2400m: device descriptor
159
* @rfss: TLV for RF Switches status; already validated
160
*
161
* NOTE: the reports on RF switch status cannot be trusted
162
* or used until the device is in a state of RADIO_OFF
163
* or greater.
164
*/
165
void
i2400m_report_tlv_rf_switches_status
(
166
struct
i2400m
*
i2400m
,
167
const
struct
i2400m_tlv_rf_switches_status
*rfss)
168
{
169
struct
device
*
dev
= i2400m_dev(i2400m);
170
enum
i2400m_rf_switch_status
hw
,
sw
;
171
enum
wimax_st
wimax_state;
172
173
sw =
le32_to_cpu
(rfss->
sw_rf_switch
);
174
hw =
le32_to_cpu
(rfss->
hw_rf_switch
);
175
176
d_fnstart
(3, dev,
"(i2400m %p rfss %p [hw %u sw %u])\n"
,
177
i2400m, rfss, hw, sw);
178
/* We only process rw switch evens when the device has been
179
* fully initialized */
180
wimax_state =
wimax_state_get
(&i2400m->
wimax_dev
);
181
if
(wimax_state <
WIMAX_ST_RADIO_OFF
) {
182
d_printf
(3, dev,
"ignoring RF switches report, state %u\n"
,
183
wimax_state);
184
goto
out
;
185
}
186
switch
(sw) {
187
case
I2400M_RF_SWITCH_ON
:
/* RF Kill disabled (radio on) */
188
wimax_report_rfkill_sw
(&i2400m->
wimax_dev
,
WIMAX_RF_ON
);
189
break
;
190
case
I2400M_RF_SWITCH_OFF
:
/* RF Kill enabled (radio off) */
191
wimax_report_rfkill_sw
(&i2400m->
wimax_dev
,
WIMAX_RF_OFF
);
192
break
;
193
default
:
194
dev_err
(dev,
"HW BUG? Unknown RF SW state 0x%x\n"
, sw);
195
}
196
197
switch
(hw) {
198
case
I2400M_RF_SWITCH_ON
:
/* RF Kill disabled (radio on) */
199
wimax_report_rfkill_hw
(&i2400m->
wimax_dev
,
WIMAX_RF_ON
);
200
break
;
201
case
I2400M_RF_SWITCH_OFF
:
/* RF Kill enabled (radio off) */
202
wimax_report_rfkill_hw
(&i2400m->
wimax_dev
,
WIMAX_RF_OFF
);
203
break
;
204
default
:
205
dev_err
(dev,
"HW BUG? Unknown RF HW state 0x%x\n"
, hw);
206
}
207
out
:
208
d_fnend
(3, dev,
"(i2400m %p rfss %p [hw %u sw %u]) = void\n"
,
209
i2400m, rfss, hw, sw);
210
}
Generated on Thu Jan 10 2013 14:08:16 for Linux Kernel by
1.8.2