2009-09-28 11:21:42

by Holger Schurig

[permalink] [raw]
Subject: [RFC] libertas: first stab at cfg80211 support

Signed-off-by: Holger Schurig <[email protected]>

---

This patch currently just create a wdev, so you can do "iw list".

I'd like to get comments if the position where I create/destroy
the wdev makes sense.

Index: linux-wl/drivers/net/wireless/Kconfig
===================================================================
--- linux-wl.orig/drivers/net/wireless/Kconfig 2009-09-28 12:06:02.000000000 +0200
+++ linux-wl/drivers/net/wireless/Kconfig 2009-09-28 12:06:30.000000000 +0200
@@ -138,6 +138,7 @@ config LIBERTAS
depends on WLAN_80211
select WIRELESS_EXT
select LIB80211
+ select CFG80211
select FW_LOADER
---help---
A library for Marvell Libertas 8xxx devices.
Index: linux-wl/drivers/net/wireless/libertas/Makefile
===================================================================
--- linux-wl.orig/drivers/net/wireless/libertas/Makefile 2009-09-28 12:06:02.000000000 +0200
+++ linux-wl/drivers/net/wireless/libertas/Makefile 2009-09-28 12:06:30.000000000 +0200
@@ -1,5 +1,5 @@
libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \
- debugfs.o persistcfg.o ethtool.o assoc.o
+ debugfs.o persistcfg.o ethtool.o assoc.o cfg.o

usb8xxx-objs += if_usb.o
libertas_cs-objs += if_cs.o
Index: linux-wl/drivers/net/wireless/libertas/dev.h
===================================================================
--- linux-wl.orig/drivers/net/wireless/libertas/dev.h 2009-09-28 12:06:02.000000000 +0200
+++ linux-wl/drivers/net/wireless/libertas/dev.h 2009-09-28 12:06:30.000000000 +0200
@@ -100,6 +100,7 @@ struct lbs_mesh_stats {

/** Private structure for the MV device */
struct lbs_private {
+ struct wireless_dev *wdev;
int mesh_open;
int mesh_fw_ver;
int infra_open;
Index: linux-wl/drivers/net/wireless/libertas/cfg.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-wl/drivers/net/wireless/libertas/cfg.h 2009-09-28 12:07:23.000000000 +0200
@@ -0,0 +1,9 @@
+#ifndef __LBS_CFG80211_H__
+#define __LBS_CFG80211_H__
+
+#include "dev.h"
+
+struct wireless_dev *lbs_wdev_alloc(int sizeof_priv, struct device *dev);
+void lbs_wdev_free(struct lbs_private *lbs);
+
+#endif
Index: linux-wl/drivers/net/wireless/libertas/cfg.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-wl/drivers/net/wireless/libertas/cfg.c 2009-09-28 12:09:06.000000000 +0200
@@ -0,0 +1,160 @@
+/*
+ * Implement cfg80211 ("iw") support.
+ *
+ * Copyright (C) 2009 M&N Solutions GmbH, 61191 Rosbach, Germany
+ * Holger Schurig <[email protected]>
+ *
+ * Based on cfg80211.h:
+ * Copyright (C) 2009 Intel Corporation <[email protected]>
+ * Samuel Ortiz <[email protected]>
+ * Zhu Yi <[email protected]>
+ */
+
+#include <net/cfg80211.h>
+
+#include "cfg.h"
+
+
+#define CHAN2G(_channel, _freq, _flags) { \
+ .band = IEEE80211_BAND_2GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_channel), \
+ .flags = (_flags), \
+ .max_antenna_gain = 0, \
+ .max_power = 30, \
+}
+
+static struct ieee80211_channel lbs_2ghz_channels[] = {
+ CHAN2G(1, 2412, 0),
+ CHAN2G(2, 2417, 0),
+ CHAN2G(3, 2422, 0),
+ CHAN2G(4, 2427, 0),
+ CHAN2G(5, 2432, 0),
+ CHAN2G(6, 2437, 0),
+ CHAN2G(7, 2442, 0),
+ CHAN2G(8, 2447, 0),
+ CHAN2G(9, 2452, 0),
+ CHAN2G(10, 2457, 0),
+ CHAN2G(11, 2462, 0),
+ CHAN2G(12, 2467, 0),
+ CHAN2G(13, 2472, 0),
+ CHAN2G(14, 2484, 0),
+};
+
+#define RATETAB_ENT(_rate, _rateid, _flags) \
+ { \
+ .bitrate = (_rate), \
+ .hw_value = (_rateid), \
+ .flags = (_flags), \
+ }
+
+
+static struct ieee80211_rate lbs_rates[] = {
+ RATETAB_ENT(10, 0x1, 0),
+ RATETAB_ENT(20, 0x2, 0),
+ RATETAB_ENT(55, 0x4, 0),
+ RATETAB_ENT(110, 0x8, 0),
+ RATETAB_ENT(60, 0x10, 0),
+ RATETAB_ENT(90, 0x20, 0),
+ RATETAB_ENT(120, 0x40, 0),
+ RATETAB_ENT(180, 0x80, 0),
+ RATETAB_ENT(240, 0x100, 0),
+ RATETAB_ENT(360, 0x200, 0),
+ RATETAB_ENT(480, 0x400, 0),
+ RATETAB_ENT(540, 0x800, 0),
+};
+
+static struct ieee80211_supported_band lbs_band_2ghz = {
+ .channels = lbs_2ghz_channels,
+ .n_channels = ARRAY_SIZE(lbs_2ghz_channels),
+ .bitrates = lbs_rates,
+ .n_bitrates = ARRAY_SIZE(lbs_rates),
+};
+
+
+static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+};
+
+
+
+static struct cfg80211_ops lbs_cfg80211_ops = {
+/* TODO
+ .change_virtual_intf = iwm_cfg80211_change_iface,
+ .add_key = iwm_cfg80211_add_key,
+ .get_key = iwm_cfg80211_get_key,
+ .del_key = iwm_cfg80211_del_key,
+ .set_default_key = iwm_cfg80211_set_default_key,
+ .get_station = iwm_cfg80211_get_station,
+ .scan = iwm_cfg80211_scan,
+ .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
+ .connect = iwm_cfg80211_connect,
+ .disconnect = iwm_cfg80211_disconnect,
+ .join_ibss = iwm_cfg80211_join_ibss,
+ .leave_ibss = iwm_cfg80211_leave_ibss,
+ .set_tx_power = iwm_cfg80211_set_txpower,
+ .get_tx_power = iwm_cfg80211_get_txpower,
+ .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
+*/
+};
+
+struct wireless_dev *lbs_wdev_alloc(int sizeof_priv, struct device *dev)
+{
+ int ret = 0;
+ struct wireless_dev *wdev;
+
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev) {
+ dev_err(dev, "Couldn't allocate wireless device\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ wdev->wiphy = wiphy_new(&lbs_cfg80211_ops,
+ sizeof(struct lbs_private) + sizeof_priv);
+ if (!wdev->wiphy) {
+ dev_err(dev, "Couldn't allocate wiphy device\n");
+ ret = -ENOMEM;
+ goto out_err_new;
+ }
+
+ set_wiphy_dev(wdev->wiphy, dev);
+ wdev->wiphy->max_scan_ssids = 1; /* TODO */
+ wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC);
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wdev->wiphy->cipher_suites = cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+ ret = wiphy_register(wdev->wiphy);
+ if (ret < 0) {
+ dev_err(dev, "Couldn't register wiphy device\n");
+ goto out_err_register;
+ }
+
+ return wdev;
+
+ out_err_register:
+ wiphy_free(wdev->wiphy);
+
+ out_err_new:
+ kfree(wdev);
+
+ return ERR_PTR(ret);
+}
+
+
+void lbs_wdev_free(struct lbs_private *lbs)
+{
+ struct wireless_dev *wdev = lbs->wdev;
+
+ if (!wdev)
+ return;
+
+ wiphy_unregister(wdev->wiphy);
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+}
Index: linux-wl/drivers/net/wireless/libertas/main.c
===================================================================
--- linux-wl.orig/drivers/net/wireless/libertas/main.c 2009-09-28 12:06:02.000000000 +0200
+++ linux-wl/drivers/net/wireless/libertas/main.c 2009-09-28 12:11:22.000000000 +0200
@@ -14,11 +14,13 @@
#include <linux/stddef.h>
#include <linux/ieee80211.h>
#include <net/iw_handler.h>
+#include <net/cfg80211.h>

#include "host.h"
#include "decl.h"
#include "dev.h"
#include "wext.h"
+#include "cfg.h"
#include "debugfs.h"
#include "scan.h"
#include "assoc.h"
@@ -1168,31 +1170,42 @@ static const struct net_device_ops lbs_n
*/
struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
{
- struct net_device *dev = NULL;
+ struct net_device *dev;
+ struct wireless_dev *wdev;
struct lbs_private *priv = NULL;

lbs_deb_enter(LBS_DEB_MAIN);

/* Allocate an Ethernet device and register it */
- dev = alloc_etherdev(sizeof(struct lbs_private));
- if (!dev) {
+ wdev = lbs_wdev_alloc(sizeof(struct lbs_private), dmdev);
+ if (IS_ERR(wdev)) {
lbs_pr_err("init wlanX device failed\n");
goto done;
}
- priv = netdev_priv(dev);
- dev->ml_priv = priv;
+ /* TODO? */
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ priv = wdev_priv(wdev);
+ priv->wdev = wdev;

if (lbs_init_adapter(priv)) {
lbs_pr_err("failed to initialize adapter structure.\n");
- goto err_init_adapter;
+ goto err_wdev;
+ }
+
+ //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
+ dev = alloc_netdev(0, "wlan%d", ether_setup);
+ if (!dev) {
+ dev_err(dmdev, "no memory for network device instance\n");
+ goto err_adapter;
}

+ dev->netdev_ops = &lbs_netdev_ops;
+ dev->ieee80211_ptr = wdev;
+ dev->ml_priv = priv;
+ SET_NETDEV_DEV(dev, dmdev);
+ wdev->netdev = dev;
priv->dev = dev;
- priv->card = card;
- priv->mesh_open = 0;
- priv->infra_open = 0;

- /* Setup the OS Interface to our functions */
dev->netdev_ops = &lbs_netdev_ops;
dev->watchdog_timeo = 5 * HZ;
dev->ethtool_ops = &lbs_ethtool_ops;
@@ -1201,7 +1214,14 @@ struct lbs_private *lbs_add_card(void *c
#endif
dev->flags |= IFF_BROADCAST | IFF_MULTICAST;

- SET_NETDEV_DEV(dev, dmdev);
+
+ // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ??
+
+
+ priv->card = card;
+ priv->mesh_open = 0;
+ priv->infra_open = 0;
+

priv->rtap_net_dev = NULL;
strcpy(dev->name, "wlan%d");
@@ -1211,7 +1231,7 @@ struct lbs_private *lbs_add_card(void *c
priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
if (IS_ERR(priv->main_thread)) {
lbs_deb_thread("Error creating main thread.\n");
- goto err_init_adapter;
+ goto err_ndev;
}

priv->work_thread = create_singlethread_workqueue("lbs_worker");
@@ -1228,9 +1248,15 @@ struct lbs_private *lbs_add_card(void *c

goto done;

-err_init_adapter:
- lbs_free_adapter(priv);
+ err_ndev:
free_netdev(dev);
+
+ err_adapter:
+ lbs_free_adapter(priv);
+
+ err_wdev:
+ lbs_wdev_free(priv);
+
priv = NULL;

done:
@@ -1277,6 +1303,7 @@ void lbs_remove_card(struct lbs_private
kthread_stop(priv->main_thread);

lbs_free_adapter(priv);
+ lbs_wdev_free(priv);

priv->dev = NULL;
free_netdev(dev);

--
M&N Solutions GmbH Ein Unternehmen der Datagroup AG
Holger Schurig
Raiffeisenstr. 10
61191 Rosbach
Tel: 06003/9141-15 Fax 06003/9141-49
http://www.mn-solutions.de/

Handelsregister Friedberg, HRB 5903
Gesch?ftsf?hrer: P.Schrittenlocher


2009-09-28 14:54:18

by Holger Schurig

[permalink] [raw]
Subject: Re: [RFC] libertas: first stab at cfg80211 support

> This seems wrong -- doesn't libertas have multiple netdevs?
> You're treating wdev == wiphy it seems here, rather than wdev
> == netdev.

Yes, it has three netdevs, but they aren't all setup at
card-initialization time.


Some details: "struct private" contains:

struct net_device *dev;
struct net_device *mesh_dev; /* Virtual device */
struct net_device *rtap_net_dev;

The old code did have an

dev = alloc_etherdev(sizeof(struct lbs_private));"

and the other two netdevs got initialized at some other location:

* priv->lbs_add_mesh() in lbs_add_mesh()
via "alloc_netdev(0, "msh%d", ether_setup)". And lbs_add_mesh()
is called only when the hardware supports this.
* rtap_net_dev is created in lbs_add_rtap() and again I haven't
change the creation of this thingy.

Please note that when I'm using the card in station mode, both
mesh_dev and rtap_net_dev are NULL. My firmware doesn't have
mesh code, and only when I set the card into monitor mode will
the rtap_net_dev created.


I kept this behavior for now: at initialzation I call:

wdev = lbs_wdev_alloc(sizeof(struct lbs_private), dmdev);
wdev->xyz = initialization;
...
dev = alloc_netdev()


For me it's not clear if I should create wdev's for mesh_dev and
rtap_net_dev as well. However, I'm not able to check the mesh
code anyway: my firmware doesn't support this. And for
rtap_net_dev I'm not sure if this shouldn't be handled
differently in a cfg80211 scenario, e.g. via
lbs_cfg80211_change_iface().

A hint of what I should then would be most welcome :-)


--
M&N Solutions GmbH Ein Unternehmen der Datagroup AG
Holger Schurig
Raiffeisenstr. 10
61191 Rosbach
Tel: 06003/9141-15 Fax 06003/9141-49
http://www.mn-solutions.de/

Handelsregister Friedberg, HRB 5903
Gesch?ftsf?hrer: P.Schrittenlocher

2009-09-28 14:57:37

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC] libertas: first stab at cfg80211 support

On Mon, 2009-09-28 at 16:54 +0200, Holger Schurig wrote:

> Yes, it has three netdevs, but they aren't all setup at
> card-initialization time.
>
>
> Some details: "struct private" contains:
>
> struct net_device *dev;
> struct net_device *mesh_dev; /* Virtual device */
> struct net_device *rtap_net_dev;
>
> The old code did have an
>
> dev = alloc_etherdev(sizeof(struct lbs_private));"
>
> and the other two netdevs got initialized at some other location:
>
> * priv->lbs_add_mesh() in lbs_add_mesh()
> via "alloc_netdev(0, "msh%d", ether_setup)". And lbs_add_mesh()
> is called only when the hardware supports this.
> * rtap_net_dev is created in lbs_add_rtap() and again I haven't
> change the creation of this thingy.
>
> Please note that when I'm using the card in station mode, both
> mesh_dev and rtap_net_dev are NULL. My firmware doesn't have
> mesh code, and only when I set the card into monitor mode will
> the rtap_net_dev created.
>
>
> I kept this behavior for now: at initialzation I call:
>
> wdev = lbs_wdev_alloc(sizeof(struct lbs_private), dmdev);
> wdev->xyz = initialization;
> ...
> dev = alloc_netdev()
>
>
> For me it's not clear if I should create wdev's for mesh_dev and
> rtap_net_dev as well. However, I'm not able to check the mesh
> code anyway: my firmware doesn't support this. And for
> rtap_net_dev I'm not sure if this shouldn't be handled
> differently in a cfg80211 scenario, e.g. via
> lbs_cfg80211_change_iface().

Interesting.

> A hint of what I should then would be most welcome :-)

It might make sense to support adding interfaces with nl80211, since
apparently it has mesh and monitor interfaces.

johannes


Attachments:
signature.asc (801.00 B)
This is a digitally signed message part

2009-09-28 15:08:08

by Holger Schurig

[permalink] [raw]
Subject: Re: [RFC] libertas: first stab at cfg80211 support

> It might make sense to support adding interfaces with nl80211,
> since apparently it has mesh and monitor interfaces.

Yes, this will eventually be added.


In the end I'd like to have all WEXT code in it's own file or
#ifdef'd and I'd like to have a working libertas_cs and
libertas_usb that don't need WEXT at all. But that will take
considerable time :-) One step towards this goal will be
monitor mode via NL80211.

Mesh-support via NL80211 must be done by someone else, I don't
have neither the knowledge, mesh nodes nor a mesh-capable
firmware. And I don't really care about mesh. So if no one else
does it, the CFG80211-only libertas-driver won't have mesh at
all.

--
M&N Solutions GmbH Ein Unternehmen der Datagroup AG
Holger Schurig
Raiffeisenstr. 10
61191 Rosbach
Tel: 06003/9141-15 Fax 06003/9141-49
http://www.mn-solutions.de/

Handelsregister Friedberg, HRB 5903
Gesch?ftsf?hrer: P.Schrittenlocher

2009-09-28 15:25:08

by Holger Schurig

[permalink] [raw]
Subject: Re: [RFC] libertas: first stab at cfg80211 support

Hmm, I see two problems with my code:

> +struct wireless_dev *lbs_wdev_alloc(int sizeof_priv, struct
device *dev)
> +{
...
> + wdev->wiphy = wiphy_new(&lbs_cfg80211_ops,
> + sizeof(struct lbs_private) + sizeof_priv);
...

and later:

> + wdev = lbs_wdev_alloc(sizeof(struct lbs_private), dmdev);

That's rubbish, I now allocate "sizeof(lbs_private)" bytes twice.



Another thing is that it might be necessary to unbundle the
call of "wiphy_new()" and wiphy_register().

I need lbs_private allocated and usable, e.g. in
lbs_start_card().

Later, in lbs_start_card(), when I query the firmware about it's
capabilites I know enought to populate wiphy->bands. Only then
should I call wiphy_register().

--
http://www.holgerschurig.de

2009-09-28 13:31:55

by Johannes Berg

[permalink] [raw]
Subject: Re: [RFC] libertas: first stab at cfg80211 support

On Mon, 2009-09-28 at 13:21 +0200, Holger Schurig wrote:
> Signed-off-by: Holger Schurig <[email protected]>
>
> ---
>
> This patch currently just create a wdev, so you can do "iw list".
>
> I'd like to get comments if the position where I create/destroy
> the wdev makes sense.
>
> Index: linux-wl/drivers/net/wireless/Kconfig
> ===================================================================
> --- linux-wl.orig/drivers/net/wireless/Kconfig 2009-09-28 12:06:02.000000000 +0200
> +++ linux-wl/drivers/net/wireless/Kconfig 2009-09-28 12:06:30.000000000 +0200
> @@ -138,6 +138,7 @@ config LIBERTAS
> depends on WLAN_80211
> select WIRELESS_EXT
> select LIB80211
> + select CFG80211
> select FW_LOADER
> ---help---
> A library for Marvell Libertas 8xxx devices.
> Index: linux-wl/drivers/net/wireless/libertas/Makefile
> ===================================================================
> --- linux-wl.orig/drivers/net/wireless/libertas/Makefile 2009-09-28 12:06:02.000000000 +0200
> +++ linux-wl/drivers/net/wireless/libertas/Makefile 2009-09-28 12:06:30.000000000 +0200
> @@ -1,5 +1,5 @@
> libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \
> - debugfs.o persistcfg.o ethtool.o assoc.o
> + debugfs.o persistcfg.o ethtool.o assoc.o cfg.o
>
> usb8xxx-objs += if_usb.o
> libertas_cs-objs += if_cs.o
> Index: linux-wl/drivers/net/wireless/libertas/dev.h
> ===================================================================
> --- linux-wl.orig/drivers/net/wireless/libertas/dev.h 2009-09-28 12:06:02.000000000 +0200
> +++ linux-wl/drivers/net/wireless/libertas/dev.h 2009-09-28 12:06:30.000000000 +0200
> @@ -100,6 +100,7 @@ struct lbs_mesh_stats {
>
> /** Private structure for the MV device */
> struct lbs_private {
> + struct wireless_dev *wdev;
> int mesh_open;
> int mesh_fw_ver;
> int infra_open;

This seems wrong -- doesn't libertas have multiple netdevs? You're
treating wdev == wiphy it seems here, rather than wdev == netdev.

johannes


Attachments:
signature.asc (801.00 B)
This is a digitally signed message part

2009-10-01 18:23:23

by Dan Williams

[permalink] [raw]
Subject: Re: [RFC] libertas: first stab at cfg80211 support

On Mon, 2009-09-28 at 13:21 +0200, Holger Schurig wrote:
> Signed-off-by: Holger Schurig <[email protected]>
>
> ---
>
> This patch currently just create a wdev, so you can do "iw list".
>
> I'd like to get comments if the position where I create/destroy
> the wdev makes sense.

Yeah, that's probably more or less it. The mesh bits are interesting,
because they aren't really mac80211 mesh, they are "special" mesh.
Perhaps we eventually want to port that over to cfg80211, but there are
special semantics with the mesh stuff that might be a problem (notably,
all encryption and rate settings are shared with the wlanX interface).

Because of that, the mesh interface is really just a shadow interface of
the normal wlanX interface, but during some calls we need to know
whether the call was done on the mesh iface or the wlanX iface, and of
course they each have different rx/tx queues. Otherwise they share the
same private struct and whatnot. That's what the "ml_priv" bits are
for. I'd dearly love to find some other way of doing this though, since
the ml_priv stuff is really fragile.

Dan


> Index: linux-wl/drivers/net/wireless/Kconfig
> ===================================================================
> --- linux-wl.orig/drivers/net/wireless/Kconfig 2009-09-28 12:06:02.000000000 +0200
> +++ linux-wl/drivers/net/wireless/Kconfig 2009-09-28 12:06:30.000000000 +0200
> @@ -138,6 +138,7 @@ config LIBERTAS
> depends on WLAN_80211
> select WIRELESS_EXT
> select LIB80211
> + select CFG80211
> select FW_LOADER
> ---help---
> A library for Marvell Libertas 8xxx devices.
> Index: linux-wl/drivers/net/wireless/libertas/Makefile
> ===================================================================
> --- linux-wl.orig/drivers/net/wireless/libertas/Makefile 2009-09-28 12:06:02.000000000 +0200
> +++ linux-wl/drivers/net/wireless/libertas/Makefile 2009-09-28 12:06:30.000000000 +0200
> @@ -1,5 +1,5 @@
> libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \
> - debugfs.o persistcfg.o ethtool.o assoc.o
> + debugfs.o persistcfg.o ethtool.o assoc.o cfg.o
>
> usb8xxx-objs += if_usb.o
> libertas_cs-objs += if_cs.o
> Index: linux-wl/drivers/net/wireless/libertas/dev.h
> ===================================================================
> --- linux-wl.orig/drivers/net/wireless/libertas/dev.h 2009-09-28 12:06:02.000000000 +0200
> +++ linux-wl/drivers/net/wireless/libertas/dev.h 2009-09-28 12:06:30.000000000 +0200
> @@ -100,6 +100,7 @@ struct lbs_mesh_stats {
>
> /** Private structure for the MV device */
> struct lbs_private {
> + struct wireless_dev *wdev;
> int mesh_open;
> int mesh_fw_ver;
> int infra_open;
> Index: linux-wl/drivers/net/wireless/libertas/cfg.h
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-wl/drivers/net/wireless/libertas/cfg.h 2009-09-28 12:07:23.000000000 +0200
> @@ -0,0 +1,9 @@
> +#ifndef __LBS_CFG80211_H__
> +#define __LBS_CFG80211_H__
> +
> +#include "dev.h"
> +
> +struct wireless_dev *lbs_wdev_alloc(int sizeof_priv, struct device *dev);
> +void lbs_wdev_free(struct lbs_private *lbs);
> +
> +#endif
> Index: linux-wl/drivers/net/wireless/libertas/cfg.c
> ===================================================================
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ linux-wl/drivers/net/wireless/libertas/cfg.c 2009-09-28 12:09:06.000000000 +0200
> @@ -0,0 +1,160 @@
> +/*
> + * Implement cfg80211 ("iw") support.
> + *
> + * Copyright (C) 2009 M&N Solutions GmbH, 61191 Rosbach, Germany
> + * Holger Schurig <[email protected]>
> + *
> + * Based on cfg80211.h:
> + * Copyright (C) 2009 Intel Corporation <[email protected]>
> + * Samuel Ortiz <[email protected]>
> + * Zhu Yi <[email protected]>
> + */
> +
> +#include <net/cfg80211.h>
> +
> +#include "cfg.h"
> +
> +
> +#define CHAN2G(_channel, _freq, _flags) { \
> + .band = IEEE80211_BAND_2GHZ, \
> + .center_freq = (_freq), \
> + .hw_value = (_channel), \
> + .flags = (_flags), \
> + .max_antenna_gain = 0, \
> + .max_power = 30, \
> +}
> +
> +static struct ieee80211_channel lbs_2ghz_channels[] = {
> + CHAN2G(1, 2412, 0),
> + CHAN2G(2, 2417, 0),
> + CHAN2G(3, 2422, 0),
> + CHAN2G(4, 2427, 0),
> + CHAN2G(5, 2432, 0),
> + CHAN2G(6, 2437, 0),
> + CHAN2G(7, 2442, 0),
> + CHAN2G(8, 2447, 0),
> + CHAN2G(9, 2452, 0),
> + CHAN2G(10, 2457, 0),
> + CHAN2G(11, 2462, 0),
> + CHAN2G(12, 2467, 0),
> + CHAN2G(13, 2472, 0),
> + CHAN2G(14, 2484, 0),
> +};
> +
> +#define RATETAB_ENT(_rate, _rateid, _flags) \
> + { \
> + .bitrate = (_rate), \
> + .hw_value = (_rateid), \
> + .flags = (_flags), \
> + }
> +
> +
> +static struct ieee80211_rate lbs_rates[] = {
> + RATETAB_ENT(10, 0x1, 0),
> + RATETAB_ENT(20, 0x2, 0),
> + RATETAB_ENT(55, 0x4, 0),
> + RATETAB_ENT(110, 0x8, 0),
> + RATETAB_ENT(60, 0x10, 0),
> + RATETAB_ENT(90, 0x20, 0),
> + RATETAB_ENT(120, 0x40, 0),
> + RATETAB_ENT(180, 0x80, 0),
> + RATETAB_ENT(240, 0x100, 0),
> + RATETAB_ENT(360, 0x200, 0),
> + RATETAB_ENT(480, 0x400, 0),
> + RATETAB_ENT(540, 0x800, 0),
> +};
> +
> +static struct ieee80211_supported_band lbs_band_2ghz = {
> + .channels = lbs_2ghz_channels,
> + .n_channels = ARRAY_SIZE(lbs_2ghz_channels),
> + .bitrates = lbs_rates,
> + .n_bitrates = ARRAY_SIZE(lbs_rates),
> +};
> +
> +
> +static const u32 cipher_suites[] = {
> + WLAN_CIPHER_SUITE_WEP40,
> + WLAN_CIPHER_SUITE_WEP104,
> + WLAN_CIPHER_SUITE_TKIP,
> + WLAN_CIPHER_SUITE_CCMP,
> +};
> +
> +
> +
> +static struct cfg80211_ops lbs_cfg80211_ops = {
> +/* TODO
> + .change_virtual_intf = iwm_cfg80211_change_iface,
> + .add_key = iwm_cfg80211_add_key,
> + .get_key = iwm_cfg80211_get_key,
> + .del_key = iwm_cfg80211_del_key,
> + .set_default_key = iwm_cfg80211_set_default_key,
> + .get_station = iwm_cfg80211_get_station,
> + .scan = iwm_cfg80211_scan,
> + .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
> + .connect = iwm_cfg80211_connect,
> + .disconnect = iwm_cfg80211_disconnect,
> + .join_ibss = iwm_cfg80211_join_ibss,
> + .leave_ibss = iwm_cfg80211_leave_ibss,
> + .set_tx_power = iwm_cfg80211_set_txpower,
> + .get_tx_power = iwm_cfg80211_get_txpower,
> + .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
> +*/
> +};
> +
> +struct wireless_dev *lbs_wdev_alloc(int sizeof_priv, struct device *dev)
> +{
> + int ret = 0;
> + struct wireless_dev *wdev;
> +
> + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
> + if (!wdev) {
> + dev_err(dev, "Couldn't allocate wireless device\n");
> + return ERR_PTR(-ENOMEM);
> + }
> +
> + wdev->wiphy = wiphy_new(&lbs_cfg80211_ops,
> + sizeof(struct lbs_private) + sizeof_priv);
> + if (!wdev->wiphy) {
> + dev_err(dev, "Couldn't allocate wiphy device\n");
> + ret = -ENOMEM;
> + goto out_err_new;
> + }
> +
> + set_wiphy_dev(wdev->wiphy, dev);
> + wdev->wiphy->max_scan_ssids = 1; /* TODO */
> + wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
> + BIT(NL80211_IFTYPE_ADHOC);
> + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz;
> + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
> + wdev->wiphy->cipher_suites = cipher_suites;
> + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
> +
> + ret = wiphy_register(wdev->wiphy);
> + if (ret < 0) {
> + dev_err(dev, "Couldn't register wiphy device\n");
> + goto out_err_register;
> + }
> +
> + return wdev;
> +
> + out_err_register:
> + wiphy_free(wdev->wiphy);
> +
> + out_err_new:
> + kfree(wdev);
> +
> + return ERR_PTR(ret);
> +}
> +
> +
> +void lbs_wdev_free(struct lbs_private *lbs)
> +{
> + struct wireless_dev *wdev = lbs->wdev;
> +
> + if (!wdev)
> + return;
> +
> + wiphy_unregister(wdev->wiphy);
> + wiphy_free(wdev->wiphy);
> + kfree(wdev);
> +}
> Index: linux-wl/drivers/net/wireless/libertas/main.c
> ===================================================================
> --- linux-wl.orig/drivers/net/wireless/libertas/main.c 2009-09-28 12:06:02.000000000 +0200
> +++ linux-wl/drivers/net/wireless/libertas/main.c 2009-09-28 12:11:22.000000000 +0200
> @@ -14,11 +14,13 @@
> #include <linux/stddef.h>
> #include <linux/ieee80211.h>
> #include <net/iw_handler.h>
> +#include <net/cfg80211.h>
>
> #include "host.h"
> #include "decl.h"
> #include "dev.h"
> #include "wext.h"
> +#include "cfg.h"
> #include "debugfs.h"
> #include "scan.h"
> #include "assoc.h"
> @@ -1168,31 +1170,42 @@ static const struct net_device_ops lbs_n
> */
> struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
> {
> - struct net_device *dev = NULL;
> + struct net_device *dev;
> + struct wireless_dev *wdev;
> struct lbs_private *priv = NULL;
>
> lbs_deb_enter(LBS_DEB_MAIN);
>
> /* Allocate an Ethernet device and register it */
> - dev = alloc_etherdev(sizeof(struct lbs_private));
> - if (!dev) {
> + wdev = lbs_wdev_alloc(sizeof(struct lbs_private), dmdev);
> + if (IS_ERR(wdev)) {
> lbs_pr_err("init wlanX device failed\n");
> goto done;
> }
> - priv = netdev_priv(dev);
> - dev->ml_priv = priv;
> + /* TODO? */
> + wdev->iftype = NL80211_IFTYPE_STATION;
> + priv = wdev_priv(wdev);
> + priv->wdev = wdev;
>
> if (lbs_init_adapter(priv)) {
> lbs_pr_err("failed to initialize adapter structure.\n");
> - goto err_init_adapter;
> + goto err_wdev;
> + }
> +
> + //TODO? dev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES);
> + dev = alloc_netdev(0, "wlan%d", ether_setup);
> + if (!dev) {
> + dev_err(dmdev, "no memory for network device instance\n");
> + goto err_adapter;
> }
>
> + dev->netdev_ops = &lbs_netdev_ops;
> + dev->ieee80211_ptr = wdev;
> + dev->ml_priv = priv;
> + SET_NETDEV_DEV(dev, dmdev);
> + wdev->netdev = dev;
> priv->dev = dev;
> - priv->card = card;
> - priv->mesh_open = 0;
> - priv->infra_open = 0;
>
> - /* Setup the OS Interface to our functions */
> dev->netdev_ops = &lbs_netdev_ops;
> dev->watchdog_timeo = 5 * HZ;
> dev->ethtool_ops = &lbs_ethtool_ops;
> @@ -1201,7 +1214,14 @@ struct lbs_private *lbs_add_card(void *c
> #endif
> dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
>
> - SET_NETDEV_DEV(dev, dmdev);
> +
> + // TODO: kzalloc + iwm_init_default_profile(iwm, iwm->umac_profile); ??
> +
> +
> + priv->card = card;
> + priv->mesh_open = 0;
> + priv->infra_open = 0;
> +
>
> priv->rtap_net_dev = NULL;
> strcpy(dev->name, "wlan%d");
> @@ -1211,7 +1231,7 @@ struct lbs_private *lbs_add_card(void *c
> priv->main_thread = kthread_run(lbs_thread, dev, "lbs_main");
> if (IS_ERR(priv->main_thread)) {
> lbs_deb_thread("Error creating main thread.\n");
> - goto err_init_adapter;
> + goto err_ndev;
> }
>
> priv->work_thread = create_singlethread_workqueue("lbs_worker");
> @@ -1228,9 +1248,15 @@ struct lbs_private *lbs_add_card(void *c
>
> goto done;
>
> -err_init_adapter:
> - lbs_free_adapter(priv);
> + err_ndev:
> free_netdev(dev);
> +
> + err_adapter:
> + lbs_free_adapter(priv);
> +
> + err_wdev:
> + lbs_wdev_free(priv);
> +
> priv = NULL;
>
> done:
> @@ -1277,6 +1303,7 @@ void lbs_remove_card(struct lbs_private
> kthread_stop(priv->main_thread);
>
> lbs_free_adapter(priv);
> + lbs_wdev_free(priv);
>
> priv->dev = NULL;
> free_netdev(dev);
>