/* 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 */