mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/lowpan/lowpan
This commit is contained in:
commit
9409172262
|
@ -56,8 +56,12 @@ HardMAC
|
|||
|
||||
See the header include/net/ieee802154_netdev.h. You have to implement Linux
|
||||
net_device, with .type = ARPHRD_IEEE802154. Data is exchanged with socket family
|
||||
code via plain sk_buffs. The control block of sk_buffs will contain additional
|
||||
info as described in the struct ieee802154_mac_cb.
|
||||
code via plain sk_buffs. On skb reception skb->cb must contain additional
|
||||
info as described in the struct ieee802154_mac_cb. During packet transmission
|
||||
the skb->cb is used to provide additional data to device's header_ops->create
|
||||
function. Be aware, that this data can be overriden later (when socket code
|
||||
submits skb to qdisc), so if you need something from that cb later, you should
|
||||
store info in the skb->data on your own.
|
||||
|
||||
To hook the MLME interface you have to populate the ml_priv field of your
|
||||
net_device with a pointer to struct ieee802154_mlme_ops instance. All fields are
|
||||
|
@ -73,3 +77,4 @@ We are going to provide intermediate layer implementing IEEE 802.15.4 MAC
|
|||
in software. This is currently WIP.
|
||||
|
||||
See header include/net/mac802154.h and several drivers in drivers/ieee802154/.
|
||||
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
#include <net/ieee802154_netdev.h>
|
||||
#include <net/ieee802154.h>
|
||||
#include <net/nl802154.h>
|
||||
#include <net/wpan-phy.h>
|
||||
|
||||
struct wpan_phy *net_to_phy(struct net_device *dev)
|
||||
{
|
||||
return container_of(dev->dev.parent, struct wpan_phy, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* fake_get_pan_id - Retrieve the PAN ID of the device.
|
||||
|
@ -113,8 +119,15 @@ static u8 fake_get_bsn(struct net_device *dev)
|
|||
* 802.15.4-2006 document.
|
||||
*/
|
||||
static int fake_assoc_req(struct net_device *dev,
|
||||
struct ieee802154_addr *addr, u8 channel, u8 cap)
|
||||
struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap)
|
||||
{
|
||||
struct wpan_phy *phy = net_to_phy(dev);
|
||||
|
||||
mutex_lock(&phy->pib_lock);
|
||||
phy->current_channel = channel;
|
||||
phy->current_page = page;
|
||||
mutex_unlock(&phy->pib_lock);
|
||||
|
||||
/* We simply emulate it here */
|
||||
return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev),
|
||||
IEEE802154_SUCCESS);
|
||||
|
@ -179,10 +192,17 @@ static int fake_disassoc_req(struct net_device *dev,
|
|||
* document, with 7.3.8 describing coordinator realignment.
|
||||
*/
|
||||
static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
|
||||
u8 channel,
|
||||
u8 channel, u8 page,
|
||||
u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx,
|
||||
u8 coord_realign)
|
||||
{
|
||||
struct wpan_phy *phy = net_to_phy(dev);
|
||||
|
||||
mutex_lock(&phy->pib_lock);
|
||||
phy->current_channel = channel;
|
||||
phy->current_page = page;
|
||||
mutex_unlock(&phy->pib_lock);
|
||||
|
||||
/* We don't emulate beacons here at all, so START should fail */
|
||||
ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER);
|
||||
return 0;
|
||||
|
@ -204,11 +224,11 @@ static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr,
|
|||
* Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document.
|
||||
*/
|
||||
static int fake_scan_req(struct net_device *dev, u8 type, u32 channels,
|
||||
u8 duration)
|
||||
u8 page, u8 duration)
|
||||
{
|
||||
u8 edl[27] = {};
|
||||
return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type,
|
||||
channels,
|
||||
channels, page,
|
||||
type == IEEE802154_MAC_SCAN_ED ? edl : NULL);
|
||||
}
|
||||
|
||||
|
@ -290,6 +310,14 @@ static const struct net_device_ops fake_ops = {
|
|||
.ndo_set_mac_address = ieee802154_fake_mac_addr,
|
||||
};
|
||||
|
||||
static void ieee802154_fake_destruct(struct net_device *dev)
|
||||
{
|
||||
struct wpan_phy *phy = net_to_phy(dev);
|
||||
|
||||
wpan_phy_unregister(phy);
|
||||
free_netdev(dev);
|
||||
wpan_phy_free(phy);
|
||||
}
|
||||
|
||||
static void ieee802154_fake_setup(struct net_device *dev)
|
||||
{
|
||||
|
@ -302,22 +330,34 @@ static void ieee802154_fake_setup(struct net_device *dev)
|
|||
dev->type = ARPHRD_IEEE802154;
|
||||
dev->flags = IFF_NOARP | IFF_BROADCAST;
|
||||
dev->watchdog_timeo = 0;
|
||||
dev->destructor = ieee802154_fake_destruct;
|
||||
}
|
||||
|
||||
|
||||
static int __devinit ieee802154fake_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *dev =
|
||||
alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup);
|
||||
struct net_device *dev;
|
||||
struct wpan_phy *phy = wpan_phy_alloc(0);
|
||||
int err;
|
||||
|
||||
if (!dev)
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
|
||||
dev = alloc_netdev(0, "hardwpan%d", ieee802154_fake_setup);
|
||||
if (!dev) {
|
||||
wpan_phy_free(phy);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
phy->dev.platform_data = dev;
|
||||
|
||||
memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef",
|
||||
dev->addr_len);
|
||||
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
|
||||
|
||||
phy->channels_supported = (1 << 27) - 1;
|
||||
phy->transmit_power = 0xbf;
|
||||
|
||||
dev->netdev_ops = &fake_ops;
|
||||
dev->ml_priv = &fake_mlme;
|
||||
|
||||
|
@ -331,15 +371,18 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev)
|
|||
goto out;
|
||||
}
|
||||
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
SET_NETDEV_DEV(dev, &phy->dev);
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
err = wpan_phy_register(&pdev->dev, phy);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = register_netdev(dev);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
|
||||
dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n");
|
||||
return 0;
|
||||
|
||||
|
@ -352,7 +395,6 @@ static int __devexit ieee802154fake_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct net_device *dev = platform_get_drvdata(pdev);
|
||||
unregister_netdev(dev);
|
||||
free_netdev(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,6 @@
|
|||
#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */
|
||||
#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */
|
||||
#define ARPHRD_IEEE802154 804
|
||||
#define ARPHRD_IEEE802154_PHY 805
|
||||
|
||||
#define ARPHRD_PHONET 820 /* PhoNet media type */
|
||||
#define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */
|
||||
|
|
|
@ -64,6 +64,8 @@ enum {
|
|||
IEEE802154_ATTR_COORD_REALIGN,
|
||||
IEEE802154_ATTR_SEC,
|
||||
|
||||
IEEE802154_ATTR_PAGE,
|
||||
|
||||
__IEEE802154_ATTR_MAX,
|
||||
};
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ static inline int mac_cb_type(struct sk_buff *skb)
|
|||
struct ieee802154_mlme_ops {
|
||||
int (*assoc_req)(struct net_device *dev,
|
||||
struct ieee802154_addr *addr,
|
||||
u8 channel, u8 cap);
|
||||
u8 channel, u8 page, u8 cap);
|
||||
int (*assoc_resp)(struct net_device *dev,
|
||||
struct ieee802154_addr *addr,
|
||||
u16 short_addr, u8 status);
|
||||
|
@ -89,10 +89,10 @@ struct ieee802154_mlme_ops {
|
|||
u8 reason);
|
||||
int (*start_req)(struct net_device *dev,
|
||||
struct ieee802154_addr *addr,
|
||||
u8 channel, u8 bcn_ord, u8 sf_ord,
|
||||
u8 channel, u8 page, u8 bcn_ord, u8 sf_ord,
|
||||
u8 pan_coord, u8 blx, u8 coord_realign);
|
||||
int (*scan_req)(struct net_device *dev,
|
||||
u8 type, u32 channels, u8 duration);
|
||||
u8 type, u32 channels, u8 page, u8 duration);
|
||||
|
||||
/*
|
||||
* FIXME: these should become the part of PIB/MIB interface.
|
||||
|
|
|
@ -95,7 +95,7 @@ int ieee802154_nl_disassoc_confirm(struct net_device *dev,
|
|||
* Note: This API does not permit the return of an active scan result.
|
||||
*/
|
||||
int ieee802154_nl_scan_confirm(struct net_device *dev,
|
||||
u8 status, u8 scan_type, u32 unscanned,
|
||||
u8 status, u8 scan_type, u32 unscanned, u8 page,
|
||||
u8 *edl/*, struct list_head *pan_desc_list */);
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (C) 2007, 2008, 2009 Siemens AG
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Written by:
|
||||
* Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef WPAN_PHY_H
|
||||
#define WPAN_PHY_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
struct wpan_phy {
|
||||
struct mutex pib_lock;
|
||||
|
||||
/*
|
||||
* This is a PIB acording to 802.15.4-2006.
|
||||
* We do not provide timing-related variables, as they
|
||||
* aren't used outside of driver
|
||||
*/
|
||||
u8 current_channel;
|
||||
u8 current_page;
|
||||
u32 channels_supported;
|
||||
u8 transmit_power;
|
||||
u8 cca_mode;
|
||||
|
||||
struct device dev;
|
||||
int idx;
|
||||
|
||||
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
|
||||
};
|
||||
|
||||
struct wpan_phy *wpan_phy_alloc(size_t priv_size);
|
||||
int wpan_phy_register(struct device *parent, struct wpan_phy *phy);
|
||||
void wpan_phy_unregister(struct wpan_phy *phy);
|
||||
void wpan_phy_free(struct wpan_phy *phy);
|
||||
|
||||
static inline void *wpan_phy_priv(struct wpan_phy *phy)
|
||||
{
|
||||
BUG_ON(!phy);
|
||||
return &phy->priv;
|
||||
}
|
||||
|
||||
struct wpan_phy *wpan_phy_find(const char *str);
|
||||
static inline const char *wpan_phy_name(struct wpan_phy *phy)
|
||||
{
|
||||
return dev_name(&phy->dev);
|
||||
}
|
||||
#endif
|
|
@ -269,7 +269,7 @@ static const unsigned short netdev_lock_type[] =
|
|||
ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL,
|
||||
ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211,
|
||||
ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET,
|
||||
ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154, ARPHRD_IEEE802154_PHY,
|
||||
ARPHRD_PHONET_PIPE, ARPHRD_IEEE802154,
|
||||
ARPHRD_VOID, ARPHRD_NONE};
|
||||
|
||||
static const char *const netdev_lock_name[] =
|
||||
|
@ -287,7 +287,7 @@ static const char *const netdev_lock_name[] =
|
|||
"_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL",
|
||||
"_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211",
|
||||
"_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET",
|
||||
"_xmit_PHONET_PIPE", "_xmit_IEEE802154", "_xmit_IEEE802154_PHY",
|
||||
"_xmit_PHONET_PIPE", "_xmit_IEEE802154",
|
||||
"_xmit_VOID", "_xmit_NONE"};
|
||||
|
||||
static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)];
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o
|
||||
obj-$(CONFIG_IEEE802154) += nl802154.o af_802154.o wpan-class.o
|
||||
nl802154-y := netlink.o nl_policy.o
|
||||
af_802154-y := af_ieee802154.o raw.o dgram.o
|
||||
|
||||
|
|
|
@ -147,9 +147,7 @@ static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
|
|||
dev_load(sock_net(sk), ifr.ifr_name);
|
||||
dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);
|
||||
|
||||
if ((dev->type == ARPHRD_IEEE802154 ||
|
||||
dev->type == ARPHRD_IEEE802154_PHY) &&
|
||||
dev->netdev_ops->ndo_do_ioctl)
|
||||
if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl)
|
||||
ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);
|
||||
|
||||
if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
|
||||
|
|
|
@ -232,7 +232,7 @@ int ieee802154_nl_beacon_indic(struct net_device *dev,
|
|||
EXPORT_SYMBOL(ieee802154_nl_beacon_indic);
|
||||
|
||||
int ieee802154_nl_scan_confirm(struct net_device *dev,
|
||||
u8 status, u8 scan_type, u32 unscanned,
|
||||
u8 status, u8 scan_type, u32 unscanned, u8 page,
|
||||
u8 *edl/* , struct list_head *pan_desc_list */)
|
||||
{
|
||||
struct sk_buff *msg;
|
||||
|
@ -251,6 +251,7 @@ int ieee802154_nl_scan_confirm(struct net_device *dev,
|
|||
NLA_PUT_U8(msg, IEEE802154_ATTR_STATUS, status);
|
||||
NLA_PUT_U8(msg, IEEE802154_ATTR_SCAN_TYPE, scan_type);
|
||||
NLA_PUT_U32(msg, IEEE802154_ATTR_CHANNELS, unscanned);
|
||||
NLA_PUT_U8(msg, IEEE802154_ATTR_PAGE, page);
|
||||
|
||||
if (edl)
|
||||
NLA_PUT(msg, IEEE802154_ATTR_ED_LIST, 27, edl);
|
||||
|
@ -349,6 +350,7 @@ static int ieee802154_associate_req(struct sk_buff *skb,
|
|||
{
|
||||
struct net_device *dev;
|
||||
struct ieee802154_addr addr;
|
||||
u8 page;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!info->attrs[IEEE802154_ATTR_CHANNEL] ||
|
||||
|
@ -374,8 +376,14 @@ static int ieee802154_associate_req(struct sk_buff *skb,
|
|||
}
|
||||
addr.pan_id = nla_get_u16(info->attrs[IEEE802154_ATTR_COORD_PAN_ID]);
|
||||
|
||||
if (info->attrs[IEEE802154_ATTR_PAGE])
|
||||
page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
|
||||
else
|
||||
page = 0;
|
||||
|
||||
ret = ieee802154_mlme_ops(dev)->assoc_req(dev, &addr,
|
||||
nla_get_u8(info->attrs[IEEE802154_ATTR_CHANNEL]),
|
||||
page,
|
||||
nla_get_u8(info->attrs[IEEE802154_ATTR_CAPABILITY]));
|
||||
|
||||
dev_put(dev);
|
||||
|
@ -458,6 +466,7 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
|
|||
struct ieee802154_addr addr;
|
||||
|
||||
u8 channel, bcn_ord, sf_ord;
|
||||
u8 page;
|
||||
int pan_coord, blx, coord_realign;
|
||||
int ret;
|
||||
|
||||
|
@ -488,13 +497,19 @@ static int ieee802154_start_req(struct sk_buff *skb, struct genl_info *info)
|
|||
blx = nla_get_u8(info->attrs[IEEE802154_ATTR_BAT_EXT]);
|
||||
coord_realign = nla_get_u8(info->attrs[IEEE802154_ATTR_COORD_REALIGN]);
|
||||
|
||||
if (info->attrs[IEEE802154_ATTR_PAGE])
|
||||
page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
|
||||
else
|
||||
page = 0;
|
||||
|
||||
|
||||
if (addr.short_addr == IEEE802154_ADDR_BROADCAST) {
|
||||
ieee802154_nl_start_confirm(dev, IEEE802154_NO_SHORT_ADDRESS);
|
||||
dev_put(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel,
|
||||
ret = ieee802154_mlme_ops(dev)->start_req(dev, &addr, channel, page,
|
||||
bcn_ord, sf_ord, pan_coord, blx, coord_realign);
|
||||
|
||||
dev_put(dev);
|
||||
|
@ -508,6 +523,7 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
|
|||
u8 type;
|
||||
u32 channels;
|
||||
u8 duration;
|
||||
u8 page;
|
||||
|
||||
if (!info->attrs[IEEE802154_ATTR_SCAN_TYPE] ||
|
||||
!info->attrs[IEEE802154_ATTR_CHANNELS] ||
|
||||
|
@ -522,7 +538,13 @@ static int ieee802154_scan_req(struct sk_buff *skb, struct genl_info *info)
|
|||
channels = nla_get_u32(info->attrs[IEEE802154_ATTR_CHANNELS]);
|
||||
duration = nla_get_u8(info->attrs[IEEE802154_ATTR_DURATION]);
|
||||
|
||||
ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels,
|
||||
if (info->attrs[IEEE802154_ATTR_PAGE])
|
||||
page = nla_get_u8(info->attrs[IEEE802154_ATTR_PAGE]);
|
||||
else
|
||||
page = 0;
|
||||
|
||||
|
||||
ret = ieee802154_mlme_ops(dev)->scan_req(dev, type, channels, page,
|
||||
duration);
|
||||
|
||||
dev_put(dev);
|
||||
|
|
|
@ -33,6 +33,7 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX + 1] = {
|
|||
[IEEE802154_ATTR_HW_ADDR] = { .type = NLA_HW_ADDR, },
|
||||
[IEEE802154_ATTR_PAN_ID] = { .type = NLA_U16, },
|
||||
[IEEE802154_ATTR_CHANNEL] = { .type = NLA_U8, },
|
||||
[IEEE802154_ATTR_PAGE] = { .type = NLA_U8, },
|
||||
[IEEE802154_ATTR_COORD_SHORT_ADDR] = { .type = NLA_U16, },
|
||||
[IEEE802154_ATTR_COORD_HW_ADDR] = { .type = NLA_HW_ADDR, },
|
||||
[IEEE802154_ATTR_COORD_PAN_ID] = { .type = NLA_U16, },
|
||||
|
|
|
@ -74,8 +74,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (dev->type != ARPHRD_IEEE802154_PHY &&
|
||||
dev->type != ARPHRD_IEEE802154) {
|
||||
if (dev->type != ARPHRD_IEEE802154) {
|
||||
err = -ENODEV;
|
||||
goto out_put;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (C) 2007, 2008, 2009 Siemens AG
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <net/wpan-phy.h>
|
||||
|
||||
#define MASTER_SHOW_COMPLEX(name, format_string, args...) \
|
||||
static ssize_t name ## _show(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); \
|
||||
int ret; \
|
||||
\
|
||||
mutex_lock(&phy->pib_lock); \
|
||||
ret = sprintf(buf, format_string "\n", args); \
|
||||
mutex_unlock(&phy->pib_lock); \
|
||||
return ret; \
|
||||
}
|
||||
|
||||
#define MASTER_SHOW(field, format_string) \
|
||||
MASTER_SHOW_COMPLEX(field, format_string, phy->field)
|
||||
|
||||
MASTER_SHOW(current_channel, "%d");
|
||||
MASTER_SHOW(current_page, "%d");
|
||||
MASTER_SHOW(channels_supported, "%#x");
|
||||
MASTER_SHOW_COMPLEX(transmit_power, "%d +- %d dB",
|
||||
((signed char) (phy->transmit_power << 2)) >> 2,
|
||||
(phy->transmit_power >> 6) ? (phy->transmit_power >> 6) * 3 : 1 );
|
||||
MASTER_SHOW(cca_mode, "%d");
|
||||
|
||||
static struct device_attribute pmib_attrs[] = {
|
||||
__ATTR_RO(current_channel),
|
||||
__ATTR_RO(current_page),
|
||||
__ATTR_RO(channels_supported),
|
||||
__ATTR_RO(transmit_power),
|
||||
__ATTR_RO(cca_mode),
|
||||
{},
|
||||
};
|
||||
|
||||
static void wpan_phy_release(struct device *d)
|
||||
{
|
||||
struct wpan_phy *phy = container_of(d, struct wpan_phy, dev);
|
||||
kfree(phy);
|
||||
}
|
||||
|
||||
static struct class wpan_phy_class = {
|
||||
.name = "ieee802154",
|
||||
.dev_release = wpan_phy_release,
|
||||
.dev_attrs = pmib_attrs,
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(wpan_phy_mutex);
|
||||
static int wpan_phy_idx;
|
||||
|
||||
static int wpan_phy_match(struct device *dev, void *data)
|
||||
{
|
||||
return !strcmp(dev_name(dev), (const char *)data);
|
||||
}
|
||||
|
||||
struct wpan_phy *wpan_phy_find(const char *str)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
if (WARN_ON(!str))
|
||||
return NULL;
|
||||
|
||||
dev = class_find_device(&wpan_phy_class, NULL,
|
||||
(void *)str, wpan_phy_match);
|
||||
if (!dev)
|
||||
return NULL;
|
||||
|
||||
return container_of(dev, struct wpan_phy, dev);
|
||||
}
|
||||
EXPORT_SYMBOL(wpan_phy_find);
|
||||
|
||||
static int wpan_phy_idx_valid(int idx)
|
||||
{
|
||||
return idx >= 0;
|
||||
}
|
||||
|
||||
struct wpan_phy *wpan_phy_alloc(size_t priv_size)
|
||||
{
|
||||
struct wpan_phy *phy = kzalloc(sizeof(*phy) + priv_size,
|
||||
GFP_KERNEL);
|
||||
|
||||
mutex_lock(&wpan_phy_mutex);
|
||||
phy->idx = wpan_phy_idx++;
|
||||
if (unlikely(!wpan_phy_idx_valid(phy->idx))) {
|
||||
wpan_phy_idx--;
|
||||
mutex_unlock(&wpan_phy_mutex);
|
||||
kfree(phy);
|
||||
return NULL;
|
||||
}
|
||||
mutex_unlock(&wpan_phy_mutex);
|
||||
|
||||
mutex_init(&phy->pib_lock);
|
||||
|
||||
device_initialize(&phy->dev);
|
||||
dev_set_name(&phy->dev, "wpan-phy%d", phy->idx);
|
||||
|
||||
phy->dev.class = &wpan_phy_class;
|
||||
|
||||
return phy;
|
||||
}
|
||||
EXPORT_SYMBOL(wpan_phy_alloc);
|
||||
|
||||
int wpan_phy_register(struct device *parent, struct wpan_phy *phy)
|
||||
{
|
||||
phy->dev.parent = parent;
|
||||
|
||||
return device_add(&phy->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(wpan_phy_register);
|
||||
|
||||
void wpan_phy_unregister(struct wpan_phy *phy)
|
||||
{
|
||||
device_del(&phy->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(wpan_phy_unregister);
|
||||
|
||||
void wpan_phy_free(struct wpan_phy *phy)
|
||||
{
|
||||
put_device(&phy->dev);
|
||||
}
|
||||
EXPORT_SYMBOL(wpan_phy_free);
|
||||
|
||||
static int __init wpan_phy_class_init(void)
|
||||
{
|
||||
return class_register(&wpan_phy_class);
|
||||
}
|
||||
subsys_initcall(wpan_phy_class_init);
|
||||
|
||||
static void __exit wpan_phy_class_exit(void)
|
||||
{
|
||||
class_unregister(&wpan_phy_class);
|
||||
}
|
||||
module_exit(wpan_phy_class_exit);
|
||||
|
||||
MODULE_DESCRIPTION("IEEE 802.15.4 device class");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
Loading…
Reference in New Issue