1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
|
/* Note : this particular snipset of code is available under
* the LGPL, MPL or BSD license (at your choice).
* Jean II
*/
/* --------------------------- INCLUDE --------------------------- */
/* Backward compatibility for Wireless Extension 9 */
#ifndef IW_POWER_MODIFIER
#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */
#define IW_POWER_MIN 0x0001 /* Value is a minimum */
#define IW_POWER_MAX 0x0002 /* Value is a maximum */
#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
#endif IW_POWER_MODIFIER
struct net_local {
int pm_on; // Power Management enabled
int pm_multi; // Receive multicasts
int pm_period; // Power Management period
int pm_period_auto; // Power Management auto mode
int pm_max_period; // Power Management max period
int pm_min_period; // Power Management min period
int pm_timeout; // Power Management timeout
};
/* --------------------------- HANDLERS --------------------------- */
static int ioctl_set_power(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *prq,
char *extra)
{
/* Disable it ? */
if(prq->disabled)
{
local->pm_on = 0;
}
else
{
/* Check mode */
switch(prq->flags & IW_POWER_MODE)
{
case IW_POWER_UNICAST_R:
local->pm_multi = 0;
local->need_commit = 1;
break;
case IW_POWER_ALL_R:
local->pm_multi = 1;
local->need_commit = 1;
break;
case IW_POWER_ON: /* None = ok */
break;
default: /* Invalid */
return(-EINVAL);
}
/* Set period */
if(prq->flags & IW_POWER_PERIOD)
{
int period = prq->value;
#if WIRELESS_EXT < 21
period /= 1000000;
#endif
/* Hum: check if within bounds... */
/* Activate PM */
local->pm_on = 1;
local->need_commit = 1;
/* Check min value */
if(prq->flags & IW_POWER_MIN)
{
local->pm_min_period = period;
local->pm_period_auto = 1;
}
else
/* Check max value */
if(prq->flags & IW_POWER_MAX)
{
local->pm_max_period = period;
local->pm_period_auto = 1;
}
else
{
/* Fixed value */
local->pm_period = period;
local->pm_period_auto = 0;
}
}
/* Set timeout */
if(prq->flags & IW_POWER_TIMEOUT)
{
/* Activate PM */
local->pm_on = 1;
local->need_commit = 1;
/* Fixed value in ms */
local->pm_timeout = prq->value/1000;
}
}
return(0);
}
static int ioctl_get_power(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *prq,
char *extra)
{
prq->disabled = !local->pm_on;
/* By default, display the period */
if(!(prq->flags & IW_POWER_TIMEOUT))
{
int inc_flags = prq->flags;
prq->flags = IW_POWER_PERIOD | IW_POWER_RELATIVE;
/* Check if auto */
if(local->pm_period_auto)
{
/* By default, the min */
if(!(inc_flags & IW_POWER_MAX))
{
prq->value = local->pm_min_period;
#if WIRELESS_EXT < 21
prq->value *= 1000000;
#endif
prq->flags |= IW_POWER_MIN;
}
else
{
prq->value = local->pm_max_period;
#if WIRELESS_EXT < 21
prq->value *= 1000000;
#endif
prq->flags |= IW_POWER_MAX;
}
}
else
{
/* Fixed value. Check the flags */
if(inc_flags & (IW_POWER_MIN | IW_POWER_MAX))
return(-EINVAL);
else
{
prq->value = local->pm_period;
#if WIRELESS_EXT < 21
prq->value *= 1000000;
#endif
}
}
}
else
{
/* Deal with the timeout - always fixed */
prq->flags = IW_POWER_TIMEOUT;
prq->value = local->pm_timeout * 1000;
}
if(local->pm_multi)
prq->flags |= IW_POWER_ALL_R;
else
prq->flags |= IW_POWER_UNICAST_R;
return(0);
}
static int ioctl_get_range(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *rrq,
char *extra)
{
struct iw_range *range = (struct iw_range *) extra;
rrq->length = sizeof(struct iw_range);
memset(range, 0, sizeof(struct iw_range));
#if WIRELESS_EXT > 10
/* Version we are compiled with */
range->we_version_compiled = WIRELESS_EXT;
/* Minimum version we recommend */
range->we_version_source = 8;
#endif /* WIRELESS_EXT > 10 */
#if WIRELESS_EXT > 9
#if WIRELESS_EXT < 21
range.min_pmp = 1000000; /* 1 units */
range.max_pmp = 12000000; /* 12 units */
#else
range.min_pmp = 1; /* 1 units */
range.max_pmp = 12; /* 12 units */
#endif
range.min_pmt = 1000; /* 1 ms */
range.max_pmt = 1000000; /* 1 s */
range.pmp_flags = IW_POWER_PERIOD | IW_POWER_RELATIVE |
IW_POWER_MIN | IW_POWER_MAX;
range.pmt_flags = IW_POWER_TIMEOUT;
range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
#endif /* WIRELESS_EXT > 9 */
return(0);
}
/* --------------------------- BINDING --------------------------- */
#if WIRELESS_EXT > 12
/* Use the new driver API, save overhead */
static const iw_handler handler_table[] =
{
...
(iw_handler) ioctl_set_power, /* SIOCSIWPOWER */
(iw_handler) ioctl_get_power, /* SIOCGIWPOWER */
};
#else /* WIRELESS_EXT < 12 */
/* Use old API in the ioctl handler */
static int
do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct iwreq *wrq = (struct iwreq *) ifr;
int err = 0;
switch (cmd)
{
#if WIRELESS_EXT > 8
/* Set the desired Power Management mode */
case SIOCSIWPOWER:
err = ioctl_set_power(dev, NULL, &(wrq->u.power), NULL);
break;
/* Get the power management settings */
case SIOCGIWPOWER:
err = ioctl_get_power(dev, NULL, &(wrq->u.power), NULL);
break;
#endif /* WIRELESS_EXT > 8 */
}
return(err);
}
#endif /* WIRELESS_EXT < 12 */
|