aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/uwb/i1480/i1480u-wlp/lc.c
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>2008-09-17 11:34:21 -0400
committerDavid Vrabel <dv02@dv02pc01.europe.root.pri>2008-09-17 11:54:28 -0400
commita21b963aa4a98c645b1fa3799f2e4a6ebb6c974a (patch)
treebb6c927dea997cd1327c283f2969263475c21674 /drivers/uwb/i1480/i1480u-wlp/lc.c
parent1ba47da527121ff704f4e9f27a12c9f32db05022 (diff)
uwb: add the i1480 WLP driver
Add the driver for the WLP capability of the Intel i1480 device. Signed-off-by: David Vrabel <david.vrabel@csr.com>
Diffstat (limited to 'drivers/uwb/i1480/i1480u-wlp/lc.c')
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/lc.c421
1 files changed, 421 insertions, 0 deletions
diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c
new file mode 100644
index 000000000000..737d60cd5b73
--- /dev/null
+++ b/drivers/uwb/i1480/i1480u-wlp/lc.c
@@ -0,0 +1,421 @@
1/*
2 * WUSB Wire Adapter: WLP interface
3 * Driver for the Linux Network stack.
4 *
5 * Copyright (C) 2005-2006 Intel Corporation
6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 *
23 * FIXME: docs
24 *
25 * This implements a very simple network driver for the WLP USB
26 * device that is associated to a UWB (Ultra Wide Band) host.
27 *
28 * This is seen as an interface of a composite device. Once the UWB
29 * host has an association to another WLP capable device, the
30 * networking interface (aka WLP) can start to send packets back and
31 * forth.
32 *
33 * Limitations:
34 *
35 * - Hand cranked; can't ifup the interface until there is an association
36 *
37 * - BW allocation very simplistic [see i1480u_mas_set() and callees].
38 *
39 *
40 * ROADMAP:
41 *
42 * ENTRY POINTS (driver model):
43 *
44 * i1480u_driver_{exit,init}(): initialization of the driver.
45 *
46 * i1480u_probe(): called by the driver code when a device
47 * matching 'i1480u_id_table' is connected.
48 *
49 * This allocs a netdev instance, inits with
50 * i1480u_add(), then registers_netdev().
51 * i1480u_init()
52 * i1480u_add()
53 *
54 * i1480u_disconnect(): device has been disconnected/module
55 * is being removed.
56 * i1480u_rm()
57 */
58#include <linux/version.h>
59#include <linux/if_arp.h>
60#include <linux/etherdevice.h>
61#include <linux/uwb/debug.h>
62#include "i1480u-wlp.h"
63
64
65
66static inline
67void i1480u_init(struct i1480u *i1480u)
68{
69 /* nothing so far... doesn't it suck? */
70 spin_lock_init(&i1480u->lock);
71 INIT_LIST_HEAD(&i1480u->tx_list);
72 spin_lock_init(&i1480u->tx_list_lock);
73 wlp_options_init(&i1480u->options);
74 edc_init(&i1480u->tx_errors);
75 edc_init(&i1480u->rx_errors);
76#ifdef i1480u_FLOW_CONTROL
77 edc_init(&i1480u->notif_edc);
78#endif
79 stats_init(&i1480u->lqe_stats);
80 stats_init(&i1480u->rssi_stats);
81 wlp_init(&i1480u->wlp);
82}
83
84/**
85 * Fill WLP device information structure
86 *
87 * The structure will contain a few character arrays, each ending with a
88 * null terminated string. Each string has to fit (excluding terminating
89 * character) into a specified range obtained from the WLP substack.
90 *
91 * It is still not clear exactly how this device information should be
92 * obtained. Until we find out we use the USB device descriptor as backup, some
93 * information elements have intuitive mappings, other not.
94 */
95static
96void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *dev_info)
97{
98 struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
99 struct usb_device *usb_dev = i1480u->usb_dev;
100 /* Treat device name and model name the same */
101 if (usb_dev->descriptor.iProduct) {
102 usb_string(usb_dev, usb_dev->descriptor.iProduct,
103 dev_info->name, sizeof(dev_info->name));
104 usb_string(usb_dev, usb_dev->descriptor.iProduct,
105 dev_info->model_name, sizeof(dev_info->model_name));
106 }
107 if (usb_dev->descriptor.iManufacturer)
108 usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
109 dev_info->manufacturer,
110 sizeof(dev_info->manufacturer));
111 scnprintf(dev_info->model_nr, sizeof(dev_info->model_nr), "%04x",
112 __le16_to_cpu(usb_dev->descriptor.bcdDevice));
113 if (usb_dev->descriptor.iSerialNumber)
114 usb_string(usb_dev, usb_dev->descriptor.iSerialNumber,
115 dev_info->serial, sizeof(dev_info->serial));
116 /* FIXME: where should we obtain category? */
117 dev_info->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER);
118 /* FIXME: Complete OUI and OUIsubdiv attributes */
119}
120
121#ifdef i1480u_FLOW_CONTROL
122/**
123 * Callback for the notification endpoint
124 *
125 * This mostly controls the xon/xoff protocol. In case of hard error,
126 * we stop the queue. If not, we always retry.
127 */
128static
129void i1480u_notif_cb(struct urb *urb, struct pt_regs *regs)
130{
131 struct i1480u *i1480u = urb->context;
132 struct usb_interface *usb_iface = i1480u->usb_iface;
133 struct device *dev = &usb_iface->dev;
134 int result;
135
136 switch (urb->status) {
137 case 0: /* Got valid data, do xon/xoff */
138 switch (i1480u->notif_buffer[0]) {
139 case 'N':
140 dev_err(dev, "XOFF STOPPING queue at %lu\n", jiffies);
141 netif_stop_queue(i1480u->net_dev);
142 break;
143 case 'A':
144 dev_err(dev, "XON STARTING queue at %lu\n", jiffies);
145 netif_start_queue(i1480u->net_dev);
146 break;
147 default:
148 dev_err(dev, "NEP: unknown data 0x%02hhx\n",
149 i1480u->notif_buffer[0]);
150 }
151 break;
152 case -ECONNRESET: /* Controlled situation ... */
153 case -ENOENT: /* we killed the URB... */
154 dev_err(dev, "NEP: URB reset/noent %d\n", urb->status);
155 goto error;
156 case -ESHUTDOWN: /* going away! */
157 dev_err(dev, "NEP: URB down %d\n", urb->status);
158 goto error;
159 default: /* Retry unless it gets ugly */
160 if (edc_inc(&i1480u->notif_edc, EDC_MAX_ERRORS,
161 EDC_ERROR_TIMEFRAME)) {
162 dev_err(dev, "NEP: URB max acceptable errors "
163 "exceeded; resetting device\n");
164 goto error_reset;
165 }
166 dev_err(dev, "NEP: URB error %d\n", urb->status);
167 break;
168 }
169 result = usb_submit_urb(urb, GFP_ATOMIC);
170 if (result < 0) {
171 dev_err(dev, "NEP: Can't resubmit URB: %d; resetting device\n",
172 result);
173 goto error_reset;
174 }
175 return;
176
177error_reset:
178 wlp_reset_all(&i1480-wlp);
179error:
180 netif_stop_queue(i1480u->net_dev);
181 return;
182}
183#endif
184
185static
186int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface)
187{
188 int result = -ENODEV;
189 struct wlp *wlp = &i1480u->wlp;
190 struct usb_device *usb_dev = interface_to_usbdev(iface);
191 struct net_device *net_dev = i1480u->net_dev;
192 struct uwb_rc *rc;
193 struct uwb_dev *uwb_dev;
194#ifdef i1480u_FLOW_CONTROL
195 struct usb_endpoint_descriptor *epd;
196#endif
197
198 i1480u->usb_dev = usb_get_dev(usb_dev);
199 i1480u->usb_iface = iface;
200 rc = uwb_rc_get_by_grandpa(&i1480u->usb_dev->dev);
201 if (rc == NULL) {
202 dev_err(&iface->dev, "Cannot get associated UWB Radio "
203 "Controller\n");
204 goto out;
205 }
206 wlp->xmit_frame = i1480u_xmit_frame;
207 wlp->fill_device_info = i1480u_fill_device_info;
208 wlp->stop_queue = i1480u_stop_queue;
209 wlp->start_queue = i1480u_start_queue;
210 result = wlp_setup(wlp, rc);
211 if (result < 0) {
212 dev_err(&iface->dev, "Cannot setup WLP\n");
213 goto error_wlp_setup;
214 }
215 result = 0;
216 ether_setup(net_dev); /* make it an etherdevice */
217 uwb_dev = &rc->uwb_dev;
218 /* FIXME: hookup address change notifications? */
219
220 memcpy(net_dev->dev_addr, uwb_dev->mac_addr.data,
221 sizeof(net_dev->dev_addr));
222
223 net_dev->hard_header_len = sizeof(struct untd_hdr_cmp)
224 + sizeof(struct wlp_tx_hdr)
225 + WLP_DATA_HLEN
226 + ETH_HLEN;
227 net_dev->mtu = 3500;
228 net_dev->tx_queue_len = 20; /* FIXME: maybe use 1000? */
229
230/* net_dev->flags &= ~IFF_BROADCAST; FIXME: BUG in firmware */
231 /* FIXME: multicast disabled */
232 net_dev->flags &= ~IFF_MULTICAST;
233 net_dev->features &= ~NETIF_F_SG;
234 net_dev->features &= ~NETIF_F_FRAGLIST;
235 /* All NETIF_F_*_CSUM disabled */
236 net_dev->features |= NETIF_F_HIGHDMA;
237 net_dev->watchdog_timeo = 5*HZ; /* FIXME: a better default? */
238
239 net_dev->open = i1480u_open;
240 net_dev->stop = i1480u_stop;
241 net_dev->hard_start_xmit = i1480u_hard_start_xmit;
242 net_dev->tx_timeout = i1480u_tx_timeout;
243 net_dev->get_stats = i1480u_get_stats;
244 net_dev->set_config = i1480u_set_config;
245 net_dev->change_mtu = i1480u_change_mtu;
246
247#ifdef i1480u_FLOW_CONTROL
248 /* Notification endpoint setup (submitted when we open the device) */
249 i1480u->notif_urb = usb_alloc_urb(0, GFP_KERNEL);
250 if (i1480u->notif_urb == NULL) {
251 dev_err(&iface->dev, "Unable to allocate notification URB\n");
252 result = -ENOMEM;
253 goto error_urb_alloc;
254 }
255 epd = &iface->cur_altsetting->endpoint[0].desc;
256 usb_fill_int_urb(i1480u->notif_urb, usb_dev,
257 usb_rcvintpipe(usb_dev, epd->bEndpointAddress),
258 i1480u->notif_buffer, sizeof(i1480u->notif_buffer),
259 i1480u_notif_cb, i1480u, epd->bInterval);
260
261#endif
262
263 i1480u->tx_inflight.max = i1480u_TX_INFLIGHT_MAX;
264 i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD;
265 i1480u->tx_inflight.restart_ts = jiffies;
266 usb_set_intfdata(iface, i1480u);
267 return result;
268
269#ifdef i1480u_FLOW_CONTROL
270error_urb_alloc:
271#endif
272 wlp_remove(wlp);
273error_wlp_setup:
274 uwb_rc_put(rc);
275out:
276 usb_put_dev(i1480u->usb_dev);
277 return result;
278}
279
280static void i1480u_rm(struct i1480u *i1480u)
281{
282 struct uwb_rc *rc = i1480u->wlp.rc;
283 usb_set_intfdata(i1480u->usb_iface, NULL);
284#ifdef i1480u_FLOW_CONTROL
285 usb_kill_urb(i1480u->notif_urb);
286 usb_free_urb(i1480u->notif_urb);
287#endif
288 wlp_remove(&i1480u->wlp);
289 uwb_rc_put(rc);
290 usb_put_dev(i1480u->usb_dev);
291}
292
293/** Just setup @net_dev's i1480u private data */
294static void i1480u_netdev_setup(struct net_device *net_dev)
295{
296 struct i1480u *i1480u = netdev_priv(net_dev);
297 /* Initialize @i1480u */
298 memset(i1480u, 0, sizeof(*i1480u));
299 i1480u_init(i1480u);
300}
301
302/**
303 * Probe a i1480u interface and register it
304 *
305 * @iface: USB interface to link to
306 * @id: USB class/subclass/protocol id
307 * @returns: 0 if ok, < 0 errno code on error.
308 *
309 * Does basic housekeeping stuff and then allocs a netdev with space
310 * for the i1480u data. Initializes, registers in i1480u, registers in
311 * netdev, ready to go.
312 */
313static int i1480u_probe(struct usb_interface *iface,
314 const struct usb_device_id *id)
315{
316 int result;
317 struct net_device *net_dev;
318 struct device *dev = &iface->dev;
319 struct i1480u *i1480u;
320
321 /* Allocate instance [calls i1480u_netdev_setup() on it] */
322 result = -ENOMEM;
323 net_dev = alloc_netdev(sizeof(*i1480u), "wlp%d", i1480u_netdev_setup);
324 if (net_dev == NULL) {
325 dev_err(dev, "no memory for network device instance\n");
326 goto error_alloc_netdev;
327 }
328 SET_NETDEV_DEV(net_dev, dev);
329 i1480u = netdev_priv(net_dev);
330 i1480u->net_dev = net_dev;
331 result = i1480u_add(i1480u, iface); /* Now setup all the wlp stuff */
332 if (result < 0) {
333 dev_err(dev, "cannot add i1480u device: %d\n", result);
334 goto error_i1480u_add;
335 }
336 result = register_netdev(net_dev); /* Okey dokey, bring it up */
337 if (result < 0) {
338 dev_err(dev, "cannot register network device: %d\n", result);
339 goto error_register_netdev;
340 }
341 i1480u_sysfs_setup(i1480u);
342 if (result < 0)
343 goto error_sysfs_init;
344 return 0;
345
346error_sysfs_init:
347 unregister_netdev(net_dev);
348error_register_netdev:
349 i1480u_rm(i1480u);
350error_i1480u_add:
351 free_netdev(net_dev);
352error_alloc_netdev:
353 return result;
354}
355
356
357/**
358 * Disconect a i1480u from the system.
359 *
360 * i1480u_stop() has been called before, so al the rx and tx contexts
361 * have been taken down already. Make sure the queue is stopped,
362 * unregister netdev and i1480u, free and kill.
363 */
364static void i1480u_disconnect(struct usb_interface *iface)
365{
366 struct i1480u *i1480u;
367 struct net_device *net_dev;
368
369 i1480u = usb_get_intfdata(iface);
370 net_dev = i1480u->net_dev;
371 netif_stop_queue(net_dev);
372#ifdef i1480u_FLOW_CONTROL
373 usb_kill_urb(i1480u->notif_urb);
374#endif
375 i1480u_sysfs_release(i1480u);
376 unregister_netdev(net_dev);
377 i1480u_rm(i1480u);
378 free_netdev(net_dev);
379}
380
381static struct usb_device_id i1480u_id_table[] = {
382 {
383 .match_flags = USB_DEVICE_ID_MATCH_DEVICE \
384 | USB_DEVICE_ID_MATCH_DEV_INFO \
385 | USB_DEVICE_ID_MATCH_INT_INFO,
386 .idVendor = 0x8086,
387 .idProduct = 0x0c3b,
388 .bDeviceClass = 0xef,
389 .bDeviceSubClass = 0x02,
390 .bDeviceProtocol = 0x02,
391 .bInterfaceClass = 0xff,
392 .bInterfaceSubClass = 0xff,
393 .bInterfaceProtocol = 0xff,
394 },
395 {},
396};
397MODULE_DEVICE_TABLE(usb, i1480u_id_table);
398
399static struct usb_driver i1480u_driver = {
400 .name = KBUILD_MODNAME,
401 .probe = i1480u_probe,
402 .disconnect = i1480u_disconnect,
403 .id_table = i1480u_id_table,
404};
405
406static int __init i1480u_driver_init(void)
407{
408 return usb_register(&i1480u_driver);
409}
410module_init(i1480u_driver_init);
411
412
413static void __exit i1480u_driver_exit(void)
414{
415 usb_deregister(&i1480u_driver);
416}
417module_exit(i1480u_driver_exit);
418
419MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
420MODULE_DESCRIPTION("i1480 Wireless UWB Link WLP networking for USB");
421MODULE_LICENSE("GPL");