]>
Commit | Line | Data |
---|---|---|
a21b963a IPG |
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 | */ | |
5a0e3ad6 | 58 | #include <linux/gfp.h> |
a21b963a IPG |
59 | #include <linux/if_arp.h> |
60 | #include <linux/etherdevice.h> | |
a01777ec | 61 | |
a21b963a IPG |
62 | #include "i1480u-wlp.h" |
63 | ||
64 | ||
65 | ||
66 | static inline | |
67 | void 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 | */ | |
95 | static | |
96 | void 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 | */ | |
128 | static | |
129 | void 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 | ||
177 | error_reset: | |
178 | wlp_reset_all(&i1480-wlp); | |
179 | error: | |
180 | netif_stop_queue(i1480u->net_dev); | |
181 | return; | |
182 | } | |
183 | #endif | |
184 | ||
c4a80d7e SH |
185 | static const struct net_device_ops i1480u_netdev_ops = { |
186 | .ndo_open = i1480u_open, | |
187 | .ndo_stop = i1480u_stop, | |
188 | .ndo_start_xmit = i1480u_hard_start_xmit, | |
189 | .ndo_tx_timeout = i1480u_tx_timeout, | |
190 | .ndo_set_config = i1480u_set_config, | |
191 | .ndo_change_mtu = i1480u_change_mtu, | |
192 | }; | |
193 | ||
a21b963a IPG |
194 | static |
195 | int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface) | |
196 | { | |
197 | int result = -ENODEV; | |
198 | struct wlp *wlp = &i1480u->wlp; | |
199 | struct usb_device *usb_dev = interface_to_usbdev(iface); | |
200 | struct net_device *net_dev = i1480u->net_dev; | |
201 | struct uwb_rc *rc; | |
202 | struct uwb_dev *uwb_dev; | |
203 | #ifdef i1480u_FLOW_CONTROL | |
204 | struct usb_endpoint_descriptor *epd; | |
205 | #endif | |
206 | ||
207 | i1480u->usb_dev = usb_get_dev(usb_dev); | |
208 | i1480u->usb_iface = iface; | |
209 | rc = uwb_rc_get_by_grandpa(&i1480u->usb_dev->dev); | |
210 | if (rc == NULL) { | |
211 | dev_err(&iface->dev, "Cannot get associated UWB Radio " | |
212 | "Controller\n"); | |
213 | goto out; | |
214 | } | |
215 | wlp->xmit_frame = i1480u_xmit_frame; | |
216 | wlp->fill_device_info = i1480u_fill_device_info; | |
217 | wlp->stop_queue = i1480u_stop_queue; | |
218 | wlp->start_queue = i1480u_start_queue; | |
e8e1594c | 219 | result = wlp_setup(wlp, rc, net_dev); |
a21b963a IPG |
220 | if (result < 0) { |
221 | dev_err(&iface->dev, "Cannot setup WLP\n"); | |
222 | goto error_wlp_setup; | |
223 | } | |
224 | result = 0; | |
225 | ether_setup(net_dev); /* make it an etherdevice */ | |
226 | uwb_dev = &rc->uwb_dev; | |
227 | /* FIXME: hookup address change notifications? */ | |
228 | ||
229 | memcpy(net_dev->dev_addr, uwb_dev->mac_addr.data, | |
230 | sizeof(net_dev->dev_addr)); | |
231 | ||
232 | net_dev->hard_header_len = sizeof(struct untd_hdr_cmp) | |
233 | + sizeof(struct wlp_tx_hdr) | |
234 | + WLP_DATA_HLEN | |
235 | + ETH_HLEN; | |
236 | net_dev->mtu = 3500; | |
237 | net_dev->tx_queue_len = 20; /* FIXME: maybe use 1000? */ | |
238 | ||
239 | /* net_dev->flags &= ~IFF_BROADCAST; FIXME: BUG in firmware */ | |
240 | /* FIXME: multicast disabled */ | |
241 | net_dev->flags &= ~IFF_MULTICAST; | |
242 | net_dev->features &= ~NETIF_F_SG; | |
243 | net_dev->features &= ~NETIF_F_FRAGLIST; | |
244 | /* All NETIF_F_*_CSUM disabled */ | |
245 | net_dev->features |= NETIF_F_HIGHDMA; | |
246 | net_dev->watchdog_timeo = 5*HZ; /* FIXME: a better default? */ | |
247 | ||
c4a80d7e | 248 | net_dev->netdev_ops = &i1480u_netdev_ops; |
a21b963a IPG |
249 | |
250 | #ifdef i1480u_FLOW_CONTROL | |
251 | /* Notification endpoint setup (submitted when we open the device) */ | |
252 | i1480u->notif_urb = usb_alloc_urb(0, GFP_KERNEL); | |
253 | if (i1480u->notif_urb == NULL) { | |
254 | dev_err(&iface->dev, "Unable to allocate notification URB\n"); | |
255 | result = -ENOMEM; | |
256 | goto error_urb_alloc; | |
257 | } | |
258 | epd = &iface->cur_altsetting->endpoint[0].desc; | |
259 | usb_fill_int_urb(i1480u->notif_urb, usb_dev, | |
260 | usb_rcvintpipe(usb_dev, epd->bEndpointAddress), | |
261 | i1480u->notif_buffer, sizeof(i1480u->notif_buffer), | |
262 | i1480u_notif_cb, i1480u, epd->bInterval); | |
263 | ||
264 | #endif | |
265 | ||
266 | i1480u->tx_inflight.max = i1480u_TX_INFLIGHT_MAX; | |
267 | i1480u->tx_inflight.threshold = i1480u_TX_INFLIGHT_THRESHOLD; | |
268 | i1480u->tx_inflight.restart_ts = jiffies; | |
269 | usb_set_intfdata(iface, i1480u); | |
270 | return result; | |
271 | ||
272 | #ifdef i1480u_FLOW_CONTROL | |
273 | error_urb_alloc: | |
274 | #endif | |
275 | wlp_remove(wlp); | |
276 | error_wlp_setup: | |
277 | uwb_rc_put(rc); | |
278 | out: | |
279 | usb_put_dev(i1480u->usb_dev); | |
280 | return result; | |
281 | } | |
282 | ||
283 | static void i1480u_rm(struct i1480u *i1480u) | |
284 | { | |
285 | struct uwb_rc *rc = i1480u->wlp.rc; | |
286 | usb_set_intfdata(i1480u->usb_iface, NULL); | |
287 | #ifdef i1480u_FLOW_CONTROL | |
288 | usb_kill_urb(i1480u->notif_urb); | |
289 | usb_free_urb(i1480u->notif_urb); | |
290 | #endif | |
291 | wlp_remove(&i1480u->wlp); | |
292 | uwb_rc_put(rc); | |
293 | usb_put_dev(i1480u->usb_dev); | |
294 | } | |
295 | ||
296 | /** Just setup @net_dev's i1480u private data */ | |
297 | static void i1480u_netdev_setup(struct net_device *net_dev) | |
298 | { | |
299 | struct i1480u *i1480u = netdev_priv(net_dev); | |
300 | /* Initialize @i1480u */ | |
301 | memset(i1480u, 0, sizeof(*i1480u)); | |
302 | i1480u_init(i1480u); | |
303 | } | |
304 | ||
305 | /** | |
306 | * Probe a i1480u interface and register it | |
307 | * | |
308 | * @iface: USB interface to link to | |
309 | * @id: USB class/subclass/protocol id | |
310 | * @returns: 0 if ok, < 0 errno code on error. | |
311 | * | |
312 | * Does basic housekeeping stuff and then allocs a netdev with space | |
313 | * for the i1480u data. Initializes, registers in i1480u, registers in | |
314 | * netdev, ready to go. | |
315 | */ | |
316 | static int i1480u_probe(struct usb_interface *iface, | |
317 | const struct usb_device_id *id) | |
318 | { | |
319 | int result; | |
320 | struct net_device *net_dev; | |
321 | struct device *dev = &iface->dev; | |
322 | struct i1480u *i1480u; | |
323 | ||
324 | /* Allocate instance [calls i1480u_netdev_setup() on it] */ | |
325 | result = -ENOMEM; | |
326 | net_dev = alloc_netdev(sizeof(*i1480u), "wlp%d", i1480u_netdev_setup); | |
327 | if (net_dev == NULL) { | |
328 | dev_err(dev, "no memory for network device instance\n"); | |
329 | goto error_alloc_netdev; | |
330 | } | |
331 | SET_NETDEV_DEV(net_dev, dev); | |
332 | i1480u = netdev_priv(net_dev); | |
333 | i1480u->net_dev = net_dev; | |
334 | result = i1480u_add(i1480u, iface); /* Now setup all the wlp stuff */ | |
335 | if (result < 0) { | |
336 | dev_err(dev, "cannot add i1480u device: %d\n", result); | |
337 | goto error_i1480u_add; | |
338 | } | |
339 | result = register_netdev(net_dev); /* Okey dokey, bring it up */ | |
340 | if (result < 0) { | |
341 | dev_err(dev, "cannot register network device: %d\n", result); | |
342 | goto error_register_netdev; | |
343 | } | |
344 | i1480u_sysfs_setup(i1480u); | |
345 | if (result < 0) | |
346 | goto error_sysfs_init; | |
347 | return 0; | |
348 | ||
349 | error_sysfs_init: | |
350 | unregister_netdev(net_dev); | |
351 | error_register_netdev: | |
352 | i1480u_rm(i1480u); | |
353 | error_i1480u_add: | |
354 | free_netdev(net_dev); | |
355 | error_alloc_netdev: | |
356 | return result; | |
357 | } | |
358 | ||
359 | ||
360 | /** | |
361 | * Disconect a i1480u from the system. | |
362 | * | |
363 | * i1480u_stop() has been called before, so al the rx and tx contexts | |
364 | * have been taken down already. Make sure the queue is stopped, | |
365 | * unregister netdev and i1480u, free and kill. | |
366 | */ | |
367 | static void i1480u_disconnect(struct usb_interface *iface) | |
368 | { | |
369 | struct i1480u *i1480u; | |
370 | struct net_device *net_dev; | |
371 | ||
372 | i1480u = usb_get_intfdata(iface); | |
373 | net_dev = i1480u->net_dev; | |
374 | netif_stop_queue(net_dev); | |
375 | #ifdef i1480u_FLOW_CONTROL | |
376 | usb_kill_urb(i1480u->notif_urb); | |
377 | #endif | |
378 | i1480u_sysfs_release(i1480u); | |
379 | unregister_netdev(net_dev); | |
380 | i1480u_rm(i1480u); | |
381 | free_netdev(net_dev); | |
382 | } | |
383 | ||
384 | static struct usb_device_id i1480u_id_table[] = { | |
385 | { | |
386 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE \ | |
387 | | USB_DEVICE_ID_MATCH_DEV_INFO \ | |
388 | | USB_DEVICE_ID_MATCH_INT_INFO, | |
389 | .idVendor = 0x8086, | |
390 | .idProduct = 0x0c3b, | |
391 | .bDeviceClass = 0xef, | |
392 | .bDeviceSubClass = 0x02, | |
393 | .bDeviceProtocol = 0x02, | |
394 | .bInterfaceClass = 0xff, | |
395 | .bInterfaceSubClass = 0xff, | |
396 | .bInterfaceProtocol = 0xff, | |
397 | }, | |
398 | {}, | |
399 | }; | |
400 | MODULE_DEVICE_TABLE(usb, i1480u_id_table); | |
401 | ||
402 | static struct usb_driver i1480u_driver = { | |
403 | .name = KBUILD_MODNAME, | |
404 | .probe = i1480u_probe, | |
405 | .disconnect = i1480u_disconnect, | |
406 | .id_table = i1480u_id_table, | |
407 | }; | |
408 | ||
409 | static int __init i1480u_driver_init(void) | |
410 | { | |
411 | return usb_register(&i1480u_driver); | |
412 | } | |
413 | module_init(i1480u_driver_init); | |
414 | ||
415 | ||
416 | static void __exit i1480u_driver_exit(void) | |
417 | { | |
418 | usb_deregister(&i1480u_driver); | |
419 | } | |
420 | module_exit(i1480u_driver_exit); | |
421 | ||
422 | MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); | |
423 | MODULE_DESCRIPTION("i1480 Wireless UWB Link WLP networking for USB"); | |
424 | MODULE_LICENSE("GPL"); |