diff options
Diffstat (limited to 'drivers/uwb')
-rw-r--r-- | drivers/uwb/Kconfig | 20 | ||||
-rw-r--r-- | drivers/uwb/Makefile | 1 | ||||
-rw-r--r-- | drivers/uwb/address.c | 5 | ||||
-rw-r--r-- | drivers/uwb/i1480/Makefile | 1 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480-wlp.h | 200 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/Makefile | 8 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h | 283 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/lc.c | 424 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/netdev.c | 331 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/rx.c | 474 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/sysfs.c | 407 | ||||
-rw-r--r-- | drivers/uwb/i1480/i1480u-wlp/tx.c | 584 | ||||
-rw-r--r-- | drivers/uwb/wlp/Makefile | 10 | ||||
-rw-r--r-- | drivers/uwb/wlp/driver.c | 43 | ||||
-rw-r--r-- | drivers/uwb/wlp/eda.c | 415 | ||||
-rw-r--r-- | drivers/uwb/wlp/messages.c | 1798 | ||||
-rw-r--r-- | drivers/uwb/wlp/sysfs.c | 708 | ||||
-rw-r--r-- | drivers/uwb/wlp/txrx.c | 354 | ||||
-rw-r--r-- | drivers/uwb/wlp/wlp-internal.h | 224 | ||||
-rw-r--r-- | drivers/uwb/wlp/wlp-lc.c | 560 | ||||
-rw-r--r-- | drivers/uwb/wlp/wss-lc.c | 962 |
21 files changed, 2 insertions, 7810 deletions
diff --git a/drivers/uwb/Kconfig b/drivers/uwb/Kconfig index bac8e7a6f17..d100f54ed65 100644 --- a/drivers/uwb/Kconfig +++ b/drivers/uwb/Kconfig @@ -12,8 +12,7 @@ menuconfig UWB technology using a wide spectrum (3.1-10.6GHz). It is optimized for in-room use (480Mbps at 2 meters, 110Mbps at 10m). It serves as the transport layer for other protocols, - such as Wireless USB (WUSB), IP (WLP) and upcoming - Bluetooth and 1394 + such as Wireless USB (WUSB). The topology is peer to peer; however, higher level protocols (such as WUSB) might impose a master/slave @@ -58,13 +57,6 @@ config UWB_WHCI To compile this driver select Y (built in) or M (module). It is safe to select any even if you do not have the hardware. -config UWB_WLP - tristate "Support WiMedia Link Protocol (Ethernet/IP over UWB)" - depends on UWB && NET - help - This is a common library for drivers that implement - networking over UWB. - config UWB_I1480U tristate "Support for Intel Wireless UWB Link 1480 HWA" depends on UWB_HWA @@ -77,14 +69,4 @@ config UWB_I1480U To compile this driver select Y (built in) or M (module). It is safe to select any even if you do not have the hardware. -config UWB_I1480U_WLP - tristate "Support for Intel Wireless UWB Link 1480 HWA's WLP interface" - depends on UWB_I1480U && UWB_WLP && NET - help - This driver enables WLP support for the i1480 when connected via - USB. WLP is the WiMedia Link Protocol, or IP over UWB. - - To compile this driver select Y (built in) or M (module). It - is safe to select any even if you don't have the hardware. - endif # UWB diff --git a/drivers/uwb/Makefile b/drivers/uwb/Makefile index 2f98d080fe7..d47dd6e2942 100644 --- a/drivers/uwb/Makefile +++ b/drivers/uwb/Makefile @@ -1,5 +1,4 @@ obj-$(CONFIG_UWB) += uwb.o -obj-$(CONFIG_UWB_WLP) += wlp/ obj-$(CONFIG_UWB_WHCI) += umc.o whci.o whc-rc.o obj-$(CONFIG_UWB_HWA) += hwa-rc.o obj-$(CONFIG_UWB_I1480U) += i1480/ diff --git a/drivers/uwb/address.c b/drivers/uwb/address.c index 973321327c4..8739c4f4d01 100644 --- a/drivers/uwb/address.c +++ b/drivers/uwb/address.c @@ -363,10 +363,7 @@ size_t __uwb_addr_print(char *buf, size_t buf_size, const unsigned char *addr, { size_t result; if (type) - result = scnprintf(buf, buf_size, - "%02x:%02x:%02x:%02x:%02x:%02x", - addr[0], addr[1], addr[2], - addr[3], addr[4], addr[5]); + result = scnprintf(buf, buf_size, "%pM", addr); else result = scnprintf(buf, buf_size, "%02x:%02x", addr[1], addr[0]); diff --git a/drivers/uwb/i1480/Makefile b/drivers/uwb/i1480/Makefile index 212bbc7d4c3..d69da1684cf 100644 --- a/drivers/uwb/i1480/Makefile +++ b/drivers/uwb/i1480/Makefile @@ -1,2 +1 @@ obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o -obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp/ diff --git a/drivers/uwb/i1480/i1480-wlp.h b/drivers/uwb/i1480/i1480-wlp.h deleted file mode 100644 index 18a8b0e4567..00000000000 --- a/drivers/uwb/i1480/i1480-wlp.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Intel 1480 Wireless UWB Link - * WLP specific definitions - * - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * 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. - * - * - * FIXME: docs - */ - -#ifndef __i1480_wlp_h__ -#define __i1480_wlp_h__ - -#include <linux/spinlock.h> -#include <linux/list.h> -#include <linux/uwb.h> -#include <linux/if_ether.h> -#include <asm/byteorder.h> - -/* New simplified header format? */ -#undef WLP_HDR_FMT_2 /* FIXME: rename */ - -/** - * Values of the Delivery ID & Type field when PCA or DRP - * - * The Delivery ID & Type field in the WLP TX header indicates whether - * the frame is PCA or DRP. This is done based on the high level bit of - * this field. - * We use this constant to test if the traffic is PCA or DRP as follows: - * if (wlp_tx_hdr_delivery_id_type(wlp_tx_hdr) & WLP_DRP) - * this is DRP traffic - * else - * this is PCA traffic - */ -enum deliver_id_type_bit { - WLP_DRP = 8, -}; - -/** - * WLP TX header - * - * Indicates UWB/WLP-specific transmission parameters for a network - * packet. - */ -struct wlp_tx_hdr { - /* dword 0 */ - struct uwb_dev_addr dstaddr; - u8 key_index; - u8 mac_params; - /* dword 1 */ - u8 phy_params; -#ifndef WLP_HDR_FMT_2 - u8 reserved; - __le16 oui01; /* FIXME: not so sure if __le16 or u8[2] */ - /* dword 2 */ - u8 oui2; /* if all LE, it could be merged */ - __le16 prid; -#endif -} __attribute__((packed)); - -static inline int wlp_tx_hdr_delivery_id_type(const struct wlp_tx_hdr *hdr) -{ - return hdr->mac_params & 0x0f; -} - -static inline int wlp_tx_hdr_ack_policy(const struct wlp_tx_hdr *hdr) -{ - return (hdr->mac_params >> 4) & 0x07; -} - -static inline int wlp_tx_hdr_rts_cts(const struct wlp_tx_hdr *hdr) -{ - return (hdr->mac_params >> 7) & 0x01; -} - -static inline void wlp_tx_hdr_set_delivery_id_type(struct wlp_tx_hdr *hdr, int id) -{ - hdr->mac_params = (hdr->mac_params & ~0x0f) | id; -} - -static inline void wlp_tx_hdr_set_ack_policy(struct wlp_tx_hdr *hdr, - enum uwb_ack_pol policy) -{ - hdr->mac_params = (hdr->mac_params & ~0x70) | (policy << 4); -} - -static inline void wlp_tx_hdr_set_rts_cts(struct wlp_tx_hdr *hdr, int rts_cts) -{ - hdr->mac_params = (hdr->mac_params & ~0x80) | (rts_cts << 7); -} - -static inline enum uwb_phy_rate wlp_tx_hdr_phy_rate(const struct wlp_tx_hdr *hdr) -{ - return hdr->phy_params & 0x0f; -} - -static inline int wlp_tx_hdr_tx_power(const struct wlp_tx_hdr *hdr) -{ - return (hdr->phy_params >> 4) & 0x0f; -} - -static inline void wlp_tx_hdr_set_phy_rate(struct wlp_tx_hdr *hdr, enum uwb_phy_rate rate) -{ - hdr->phy_params = (hdr->phy_params & ~0x0f) | rate; -} - -static inline void wlp_tx_hdr_set_tx_power(struct wlp_tx_hdr *hdr, int pwr) -{ - hdr->phy_params = (hdr->phy_params & ~0xf0) | (pwr << 4); -} - - -/** - * WLP RX header - * - * Provides UWB/WLP-specific transmission data for a received - * network packet. - */ -struct wlp_rx_hdr { - /* dword 0 */ - struct uwb_dev_addr dstaddr; - struct uwb_dev_addr srcaddr; - /* dword 1 */ - u8 LQI; - s8 RSSI; - u8 reserved3; -#ifndef WLP_HDR_FMT_2 - u8 oui0; - /* dword 2 */ - __le16 oui12; - __le16 prid; -#endif -} __attribute__((packed)); - - -/** User configurable options for WLP */ -struct wlp_options { - struct mutex mutex; /* access to user configurable options*/ - struct wlp_tx_hdr def_tx_hdr; /* default tx hdr */ - u8 pca_base_priority; - u8 bw_alloc; /*index into bw_allocs[] for PCA/DRP reservations*/ -}; - - -static inline -void wlp_options_init(struct wlp_options *options) -{ - mutex_init(&options->mutex); - wlp_tx_hdr_set_ack_policy(&options->def_tx_hdr, UWB_ACK_INM); - wlp_tx_hdr_set_rts_cts(&options->def_tx_hdr, 1); - /* FIXME: default to phy caps */ - wlp_tx_hdr_set_phy_rate(&options->def_tx_hdr, UWB_PHY_RATE_480); -#ifndef WLP_HDR_FMT_2 - options->def_tx_hdr.prid = cpu_to_le16(0x0000); -#endif -} - - -/* sysfs helpers */ - -extern ssize_t uwb_pca_base_priority_store(struct wlp_options *, - const char *, size_t); -extern ssize_t uwb_pca_base_priority_show(const struct wlp_options *, char *); -extern ssize_t uwb_bw_alloc_store(struct wlp_options *, const char *, size_t); -extern ssize_t uwb_bw_alloc_show(const struct wlp_options *, char *); -extern ssize_t uwb_ack_policy_store(struct wlp_options *, - const char *, size_t); -extern ssize_t uwb_ack_policy_show(const struct wlp_options *, char *); -extern ssize_t uwb_rts_cts_store(struct wlp_options *, const char *, size_t); -extern ssize_t uwb_rts_cts_show(const struct wlp_options *, char *); -extern ssize_t uwb_phy_rate_store(struct wlp_options *, const char *, size_t); -extern ssize_t uwb_phy_rate_show(const struct wlp_options *, char *); - - -/** Simple bandwidth allocation (temporary and too simple) */ -struct wlp_bw_allocs { - const char *name; - struct { - u8 mask, stream; - } tx, rx; -}; - - -#endif /* #ifndef __i1480_wlp_h__ */ diff --git a/drivers/uwb/i1480/i1480u-wlp/Makefile b/drivers/uwb/i1480/i1480u-wlp/Makefile deleted file mode 100644 index fe6709b8e68..00000000000 --- a/drivers/uwb/i1480/i1480u-wlp/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -obj-$(CONFIG_UWB_I1480U_WLP) += i1480u-wlp.o - -i1480u-wlp-objs := \ - lc.o \ - netdev.o \ - rx.o \ - sysfs.o \ - tx.o diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h deleted file mode 100644 index 2e31f536a34..00000000000 --- a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Intel 1480 Wireless UWB Link USB - * Header formats, constants, general internal interfaces - * - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * 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. - * - * - * This is not an standard interface. - * - * FIXME: docs - * - * i1480u-wlp is pretty simple: two endpoints, one for tx, one for - * rx. rx is polled. Network packets (ethernet, whatever) are wrapped - * in i1480 TX or RX headers (for sending over the air), and these - * packets are wrapped in UNTD headers (for sending to the WLP UWB - * controller). - * - * UNTD packets (UNTD hdr + i1480 hdr + network packet) packets - * cannot be bigger than i1480u_MAX_FRG_SIZE. When this happens, the - * i1480 packet is broken in chunks/packets: - * - * UNTD-1st.hdr + i1480.hdr + payload - * UNTD-next.hdr + payload - * ... - * UNTD-last.hdr + payload - * - * so that each packet is smaller or equal than i1480u_MAX_FRG_SIZE. - * - * All HW structures and bitmaps are little endian, so we need to play - * ugly tricks when defining bitfields. Hoping for the day GCC - * implements __attribute__((endian(1234))). - * - * FIXME: ROADMAP to the whole implementation - */ - -#ifndef __i1480u_wlp_h__ -#define __i1480u_wlp_h__ - -#include <linux/usb.h> -#include <linux/netdevice.h> -#include <linux/uwb.h> /* struct uwb_rc, struct uwb_notifs_handler */ -#include <linux/wlp.h> -#include "../i1480-wlp.h" - -#undef i1480u_FLOW_CONTROL /* Enable flow control code */ - -/** - * Basic flow control - */ -enum { - i1480u_TX_INFLIGHT_MAX = 1000, - i1480u_TX_INFLIGHT_THRESHOLD = 100, -}; - -/** Maximum size of a transaction that we can tx/rx */ -enum { - /* Maximum packet size computed as follows: max UNTD header (8) + - * i1480 RX header (8) + max Ethernet header and payload (4096) + - * Padding added by skb_reserve (2) to make post Ethernet payload - * start on 16 byte boundary*/ - i1480u_MAX_RX_PKT_SIZE = 4114, - i1480u_MAX_FRG_SIZE = 512, - i1480u_RX_BUFS = 9, -}; - - -/** - * UNTD packet type - * - * We need to fragment any payload whose UNTD packet is going to be - * bigger than i1480u_MAX_FRG_SIZE. - */ -enum i1480u_pkt_type { - i1480u_PKT_FRAG_1ST = 0x1, - i1480u_PKT_FRAG_NXT = 0x0, - i1480u_PKT_FRAG_LST = 0x2, - i1480u_PKT_FRAG_CMP = 0x3 -}; -enum { - i1480u_PKT_NONE = 0x4, -}; - -/** USB Network Transfer Descriptor - common */ -struct untd_hdr { - u8 type; - __le16 len; -} __attribute__((packed)); - -static inline enum i1480u_pkt_type untd_hdr_type(const struct untd_hdr *hdr) -{ - return hdr->type & 0x03; -} - -static inline int untd_hdr_rx_tx(const struct untd_hdr *hdr) -{ - return (hdr->type >> 2) & 0x01; -} - -static inline void untd_hdr_set_type(struct untd_hdr *hdr, enum i1480u_pkt_type type) -{ - hdr->type = (hdr->type & ~0x03) | type; -} - -static inline void untd_hdr_set_rx_tx(struct untd_hdr *hdr, int rx_tx) -{ - hdr->type = (hdr->type & ~0x04) | (rx_tx << 2); -} - - -/** - * USB Network Transfer Descriptor - Complete Packet - * - * This is for a packet that is smaller (header + payload) than - * i1480u_MAX_FRG_SIZE. - * - * @hdr.total_len is the size of the payload; the payload doesn't - * count this header nor the padding, but includes the size of i1480 - * header. - */ -struct untd_hdr_cmp { - struct untd_hdr hdr; - u8 padding; -} __attribute__((packed)); - - -/** - * USB Network Transfer Descriptor - First fragment - * - * @hdr.len is the size of the *whole packet* (excluding UNTD - * headers); @fragment_len is the size of the payload (excluding UNTD - * headers, but including i1480 headers). - */ -struct untd_hdr_1st { - struct untd_hdr hdr; - __le16 fragment_len; - u8 padding[3]; -} __attribute__((packed)); - - -/** - * USB Network Transfer Descriptor - Next / Last [Rest] - * - * @hdr.len is the size of the payload, not including headrs. - */ -struct untd_hdr_rst { - struct untd_hdr hdr; - u8 padding; -} __attribute__((packed)); - - -/** - * Transmission context - * - * Wraps all the stuff needed to track a pending/active tx - * operation. - */ -struct i1480u_tx { - struct list_head list_node; - struct i1480u *i1480u; - struct urb *urb; - - struct sk_buff *skb; - struct wlp_tx_hdr *wlp_tx_hdr; - - void *buf; /* if NULL, no new buf was used */ - size_t buf_size; -}; - -/** - * Basic flow control - * - * We maintain a basic flow control counter. "count" how many TX URBs are - * outstanding. Only allow "max" - * TX URBs to be outstanding. If this value is reached the queue will be - * stopped. The queue will be restarted when there are - * "threshold" URBs outstanding. - * Maintain a counter of how many time the TX queue needed to be restarted - * due to the "max" being exceeded and the "threshold" reached again. The - * timestamp "restart_ts" is to keep track from when the counter was last - * queried (see sysfs handling of file wlp_tx_inflight). - */ -struct i1480u_tx_inflight { - atomic_t count; - unsigned long max; - unsigned long threshold; - unsigned long restart_ts; - atomic_t restart_count; -}; - -/** - * Instance of a i1480u WLP interface - * - * Keeps references to the USB device that wraps it, as well as it's - * interface and associated UWB host controller. As well, it also - * keeps a link to the netdevice for integration into the networking - * stack. - * We maintian separate error history for the tx and rx endpoints because - * the implementation does not rely on locking - having one shared - * structure between endpoints may cause problems. Adding locking to the - * implementation will have higher cost than adding a separate structure. - */ -struct i1480u { - struct usb_device *usb_dev; - struct usb_interface *usb_iface; - struct net_device *net_dev; - - spinlock_t lock; - - /* RX context handling */ - struct sk_buff *rx_skb; - struct uwb_dev_addr rx_srcaddr; - size_t rx_untd_pkt_size; - struct i1480u_rx_buf { - struct i1480u *i1480u; /* back pointer */ - struct urb *urb; - struct sk_buff *data; /* i1480u_MAX_RX_PKT_SIZE each */ - } rx_buf[i1480u_RX_BUFS]; /* N bufs */ - - spinlock_t tx_list_lock; /* TX context */ - struct list_head tx_list; - u8 tx_stream; - - struct stats lqe_stats, rssi_stats; /* radio statistics */ - - /* Options we can set from sysfs */ - struct wlp_options options; - struct uwb_notifs_handler uwb_notifs_handler; - struct edc tx_errors; - struct edc rx_errors; - struct wlp wlp; -#ifdef i1480u_FLOW_CONTROL - struct urb *notif_urb; - struct edc notif_edc; /* error density counter */ - u8 notif_buffer[1]; -#endif - struct i1480u_tx_inflight tx_inflight; -}; - -/* Internal interfaces */ -extern void i1480u_rx_cb(struct urb *urb); -extern int i1480u_rx_setup(struct i1480u *); -extern void i1480u_rx_release(struct i1480u *); -extern void i1480u_tx_release(struct i1480u *); -extern int i1480u_xmit_frame(struct wlp *, struct sk_buff *, - struct uwb_dev_addr *); -extern void i1480u_stop_queue(struct wlp *); -extern void i1480u_start_queue(struct wlp *); -extern int i1480u_sysfs_setup(struct i1480u *); -extern void i1480u_sysfs_release(struct i1480u *); - -/* netdev interface */ -extern int i1480u_open(struct net_device *); -extern int i1480u_stop(struct net_device *); -extern netdev_tx_t i1480u_hard_start_xmit(struct sk_buff *, - struct net_device *); -extern void i1480u_tx_timeout(struct net_device *); -extern int i1480u_set_config(struct net_device *, struct ifmap *); -extern int i1480u_change_mtu(struct net_device *, int); -extern void i1480u_uwb_notifs_cb(void *, struct uwb_dev *, enum uwb_notifs); - -/* bandwidth allocation callback */ -extern void i1480u_bw_alloc_cb(struct uwb_rsv *); - -/* Sys FS */ -extern struct attribute_group i1480u_wlp_attr_group; - -#endif /* #ifndef __i1480u_wlp_h__ */ diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c deleted file mode 100644 index def778cf221..00000000000 --- a/drivers/uwb/i1480/i1480u-wlp/lc.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * WUSB Wire Adapter: WLP interface - * Driver for the Linux Network stack. - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * 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. - * - * - * FIXME: docs - * - * This implements a very simple network driver for the WLP USB - * device that is associated to a UWB (Ultra Wide Band) host. - * - * This is seen as an interface of a composite device. Once the UWB - * host has an association to another WLP capable device, the - * networking interface (aka WLP) can start to send packets back and - * forth. - * - * Limitations: - * - * - Hand cranked; can't ifup the interface until there is an association - * - * - BW allocation very simplistic [see i1480u_mas_set() and callees]. - * - * - * ROADMAP: - * - * ENTRY POINTS (driver model): - * - * i1480u_driver_{exit,init}(): initialization of the driver. - * - * i1480u_probe(): called by the driver code when a device - * matching 'i1480u_id_table' is connected. - * - * This allocs a netdev instance, inits with - * i1480u_add(), then registers_netdev(). - * i1480u_init() - * i1480u_add() - * - * i1480u_disconnect(): device has been disconnected/module - * is being removed. - * i1480u_rm() - */ -#include <linux/gfp.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> - -#include "i1480u-wlp.h" - - - -static inline -void i1480u_init(struct i1480u *i1480u) -{ - /* nothing so far... doesn't it suck? */ - spin_lock_init(&i1480u->lock); - INIT_LIST_HEAD(&i1480u->tx_list); - spin_lock_init(&i1480u->tx_list_lock); - wlp_options_init(&i1480u->options); - edc_init(&i1480u->tx_errors); - edc_init(&i1480u->rx_errors); -#ifdef i1480u_FLOW_CONTROL - edc_init(&i1480u->notif_edc); -#endif - stats_init(&i1480u->lqe_stats); - stats_init(&i1480u->rssi_stats); - wlp_init(&i1480u->wlp); -} - -/** - * Fill WLP device information structure - * - * The structure will contain a few character arrays, each ending with a - * null terminated string. Each string has to fit (excluding terminating - * character) into a specified range obtained from the WLP substack. - * - * It is still not clear exactly how this device information should be - * obtained. Until we find out we use the USB device descriptor as backup, some - * information elements have intuitive mappings, other not. - */ -static -void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *dev_info) -{ - struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp); - struct usb_device *usb_dev = i1480u->usb_dev; - /* Treat device name and model name the same */ - if (usb_dev->descriptor.iProduct) { - usb_string(usb_dev, usb_dev->descriptor.iProduct, - dev_info->name, sizeof(dev_info->name)); - usb_string(usb_dev, usb_dev->descriptor.iProduct, - dev_info->model_name, sizeof(dev_info->model_name)); - } - if (usb_dev->descriptor.iManufacturer) - usb_string(usb_dev, usb_dev->descriptor.iManufacturer, - dev_info->manufacturer, - sizeof(dev_info->manufacturer)); - scnprintf(dev_info->model_nr, sizeof(dev_info->model_nr), "%04x", - __le16_to_cpu(usb_dev->descriptor.bcdDevice)); - if (usb_dev->descriptor.iSerialNumber) - usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, - dev_info->serial, sizeof(dev_info->serial)); - /* FIXME: where should we obtain category? */ - dev_info->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER); - /* FIXME: Complete OUI and OUIsubdiv attributes */ -} - -#ifdef i1480u_FLOW_CONTROL -/** - * Callback for the notification endpoint - * - * This mostly controls the xon/xoff protocol. In case of hard error, - * we stop the queue. If not, we always retry. - */ -static -void i1480u_notif_cb(struct urb *urb, struct pt_regs *regs) -{ - struct i1480u *i1480u = urb->context; - struct usb_interface *usb_iface = i1480u->usb_iface; - struct device *dev = &usb_iface->dev; - int result; - - switch (urb->status) { - case 0: /* Got valid data, do xon/xoff */ - switch (i1480u->notif_buffer[0]) { - case 'N': - dev_err(dev, "XOFF STOPPING queue at %lu\n", jiffies); - netif_stop_queue(i1480u->net_dev); - break; - case 'A': - dev_err(dev, "XON STARTING queue at %lu\n", jiffies); - netif_start_queue(i1480u->net_dev); - break; - default: - dev_err(dev, "NEP: unknown data 0x%02hhx\n", - i1480u->notif_buffer[0]); - } - break; - case -ECONNRESET: /* Controlled situation ... */ - case -ENOENT: /* we killed the URB... */ - dev_err(dev, "NEP: URB reset/noent %d\n", urb->status); - goto error; - case -ESHUTDOWN: /* going away! */ - dev_err(dev, "NEP: URB down %d\n", urb->status); - goto error; - default: /* Retry unless it gets ugly */ - if (edc_inc(&i1480u->notif_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)) { - dev_err(dev, "NEP: URB max acceptable errors " - "exceeded; resetting device\n"); - goto error_reset; - } - dev_err(dev, "NEP: URB error %d\n", urb->status); - break; - } - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result < 0) { - dev_err(dev, "NEP: Can't resubmit URB: %d; resetting device\n", - result); - goto error_reset; - } - return; - -error_reset: - wlp_reset_all(&i1480-wlp); -error: - netif_stop_queue(i1480u->net_dev); - return; -} -#endif - -static const struct net_device_ops i1480u_netdev_ops = { - .ndo_open = i1480u_open, - .ndo_stop = i1480u_stop, - .ndo_start_xmit = i1480u_hard_start_xmit, - .ndo_tx_timeout = i1480u_tx_timeout, - .ndo_set_config = i1480u_set_config, - .ndo_change_mtu = i1480u_change_mtu, -}; - -static -int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface) -{ - int result = -ENODEV; - struct wlp *wlp = &i1480u->wlp; - struct usb_device *usb_dev = interface_to_usbdev(iface); - struct net_device *net_dev = i1480u->net_dev; - struct uwb_rc *rc; - struct uwb_dev *uwb_dev; -#ifdef i1480u_FLOW_CONTROL - struct usb_endpoint_descriptor *epd; -#endif - - i1480u->usb_dev = usb_get_dev(usb_dev); - i1480u->usb_iface = iface; - rc = uwb_rc_get_by_grandpa(&i1480u->usb_dev->dev); - if (rc == NULL) { - dev_err(&iface->dev, "Cannot get associated UWB Radio " - "Controller\n"); - goto out; - } - wlp->xmit_frame = i1480u_xmit_frame; - wlp->fill_device_info = i1480u_fill_device_info; - wlp->stop_queue = i1480u_stop_queue; - wlp->start_queue = i1480u_start_queue; - result = wlp_setup(wlp, rc, net_dev); - if (result < 0) { - dev_err(&iface->dev, "Cannot setup WLP\n"); - goto error_wlp_setup; - } - result = 0; - ether_setup(net_dev); /* make it an etherdevice */ - uwb_dev = &rc->uwb_dev; - /* FIXME: hookup address change notifications? */ - - memcpy(net_dev->dev_addr, uwb_dev->mac_addr.data, - sizeof(net_dev->dev_addr)); - - net_dev->hard_header_len = sizeof(struct untd_hdr_cmp) - + sizeof(struct wlp_tx_hdr) - + WLP_DATA_HLEN - + ETH_HLEN; - net_dev->mtu = 3500; - net_dev->tx_queue_len = 20; /* FIXME: maybe use 1000? */ - -/* net_dev->flags &= ~IFF_BROADCAST; FIXME: BUG in firmware */ - /* FIXME: multicast disabled */ - net_dev->flags &= ~IFF_MULTICAST; - net_dev->features &= ~NETIF_F_SG; - net_dev->features &= ~NETIF_F_FRAGLIST; - /* All NETIF_F_*_CSUM disabled */ - net_dev->features |= NETIF_F_HIGHDMA; - net_dev->watchdog_timeo = 5*HZ; /* FIXME: a better default? */ - - net_dev->netdev_ops = &i1480u_netdev_ops; - -#ifdef i1480u_FLOW_CONTROL - /* Notification endpoint setup (submitted when we open the device) */ - i1480u->notif_urb = usb_alloc_urb(0, GFP_KERNEL); - if (i1480u->notif_urb == NULL) { - dev_err(&iface->dev, "Unable to allocate notification URB\n"); - result = -ENOMEM; - goto error_urb_alloc; - } - epd = &iface->cur_altsetting->endpoint[0].desc; - usb_fill_int_urb(i1480u->notif_urb, usb_dev, - usb_rcvintpipe(usb_dev, epd->bEndpointAddress), - i1480u->notif_buffer, sizeof(i1480u->notif_buffer), - i1480u_notif_cb, i1480u, epd->bInterval); - -#endif - - i1480u->tx_inflight.max = i1480u_TX_INFLIGHT_MAX; - i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD; - i1480u->tx_inflight.restart_ts = jiffies; - usb_set_intfdata(iface, i1480u); - return result; - -#ifdef i1480u_FLOW_CONTROL -error_urb_alloc: -#endif - wlp_remove(wlp); -error_wlp_setup: - uwb_rc_put(rc); -out: - usb_put_dev(i1480u->usb_dev); - return result; -} - -static void i1480u_rm(struct i1480u *i1480u) -{ - struct uwb_rc *rc = i1480u->wlp.rc; - usb_set_intfdata(i1480u->usb_iface, NULL); -#ifdef i1480u_FLOW_CONTROL - usb_kill_urb(i1480u->notif_urb); - usb_free_urb(i1480u->notif_urb); -#endif - wlp_remove(&i1480u->wlp); - uwb_rc_put(rc); - usb_put_dev(i1480u->usb_dev); -} - -/** Just setup @net_dev's i1480u private data */ -static void i1480u_netdev_setup(struct net_device *net_dev) -{ - struct i1480u *i1480u = netdev_priv(net_dev); - /* Initialize @i1480u */ - memset(i1480u, 0, sizeof(*i1480u)); - i1480u_init(i1480u); -} - -/** - * Probe a i1480u interface and register it - * - * @iface: USB interface to link to - * @id: USB class/subclass/protocol id - * @returns: 0 if ok, < 0 errno code on error. - * - * Does basic housekeeping stuff and then allocs a netdev with space - * for the i1480u data. Initializes, registers in i1480u, registers in - * netdev, ready to go. - */ -static int i1480u_probe(struct usb_interface *iface, - const struct usb_device_id *id) -{ - int result; - struct net_device *net_dev; - struct device *dev = &iface->dev; - struct i1480u *i1480u; - - /* Allocate instance [calls i1480u_netdev_setup() on it] */ - result = -ENOMEM; - net_dev = alloc_netdev(sizeof(*i1480u), "wlp%d", i1480u_netdev_setup); - if (net_dev == NULL) { - dev_err(dev, "no memory for network device instance\n"); - goto error_alloc_netdev; - } - SET_NETDEV_DEV(net_dev, dev); - i1480u = netdev_priv(net_dev); - i1480u->net_dev = net_dev; - result = i1480u_add(i1480u, iface); /* Now setup all the wlp stuff */ - if (result < 0) { - dev_err(dev, "cannot add i1480u device: %d\n", result); - goto error_i1480u_add; - } - result = register_netdev(net_dev); /* Okey dokey, bring it up */ - if (result < 0) { - dev_err(dev, "cannot register network device: %d\n", result); - goto error_register_netdev; - } - i1480u_sysfs_setup(i1480u); - if (result < 0) - goto error_sysfs_init; - return 0; - -error_sysfs_init: - unregister_netdev(net_dev); -error_register_netdev: - i1480u_rm(i1480u); -error_i1480u_add: - free_netdev(net_dev); -error_alloc_netdev: - return result; -} - - -/** - * Disconect a i1480u from the system. - * - * i1480u_stop() has been called before, so al the rx and tx contexts - * have been taken down already. Make sure the queue is stopped, - * unregister netdev and i1480u, free and kill. |