OSDN Git Service

v25
[android-x86/external-wireless-tools.git] / wireless_tools / sample_pm.c
diff --git a/wireless_tools/sample_pm.c b/wireless_tools/sample_pm.c
new file mode 100644 (file)
index 0000000..8735cc8
--- /dev/null
@@ -0,0 +1,215 @@
+/* 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/1000000;
+         /* 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 * 1000000;
+             prq->flags |= IW_POWER_MIN;
+           }
+         else
+           {
+             prq->value = local->pm_max_period * 1000000;
+             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 * 1000000;
+       }
+    }
+  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
+      range.min_pmp = 1000000; /* 1 units */
+      range.max_pmp = 12000000;        /* 12 units */
+      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 */
+