1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /**************************************************************** |
3 | * |
4 | * kaweth.c - driver for KL5KUSB101 based USB->Ethernet |
5 | * |
6 | * (c) 2000 Interlan Communications |
7 | * (c) 2000 Stephane Alnet |
8 | * (C) 2001 Brad Hards |
9 | * (C) 2002 Oliver Neukum |
10 | * |
11 | * Original author: The Zapman <zapman@interlan.net> |
12 | * Inspired by, and much credit goes to Michael Rothwell |
13 | * <rothwell@interlan.net> for the test equipment, help, and patience |
14 | * Based off of (and with thanks to) Petko Manolov's pegaus.c driver. |
15 | * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki |
16 | * for providing the firmware and driver resources. |
17 | * |
18 | ****************************************************************/ |
19 | |
20 | /* TODO: |
21 | * Develop test procedures for USB net interfaces |
22 | * Run test procedures |
23 | * Fix bugs from previous two steps |
24 | * Snoop other OSs for any tricks we're not doing |
25 | * Reduce arbitrary timeouts |
26 | * Smart multicast support |
27 | * Temporary MAC change support |
28 | * Tunable SOFs parameter - ioctl()? |
29 | * Ethernet stats collection |
30 | * Code formatting improvements |
31 | */ |
32 | |
33 | #include <linux/module.h> |
34 | #include <linux/slab.h> |
35 | #include <linux/string.h> |
36 | #include <linux/delay.h> |
37 | #include <linux/netdevice.h> |
38 | #include <linux/etherdevice.h> |
39 | #include <linux/usb.h> |
40 | #include <linux/types.h> |
41 | #include <linux/ethtool.h> |
42 | #include <linux/dma-mapping.h> |
43 | #include <linux/wait.h> |
44 | #include <linux/firmware.h> |
45 | #include <linux/uaccess.h> |
46 | #include <asm/byteorder.h> |
47 | |
48 | #undef DEBUG |
49 | |
50 | #define KAWETH_MTU 1514 |
51 | #define KAWETH_BUF_SIZE 1664 |
52 | #define KAWETH_TX_TIMEOUT (5 * HZ) |
53 | #define KAWETH_SCRATCH_SIZE 32 |
54 | #define KAWETH_FIRMWARE_BUF_SIZE 4096 |
55 | #define KAWETH_CONTROL_TIMEOUT (30000) |
56 | |
57 | #define KAWETH_STATUS_BROKEN 0x0000001 |
58 | #define KAWETH_STATUS_CLOSING 0x0000002 |
59 | #define KAWETH_STATUS_SUSPENDING 0x0000004 |
60 | |
61 | #define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING) |
62 | |
63 | #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 |
64 | #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 |
65 | #define KAWETH_PACKET_FILTER_DIRECTED 0x04 |
66 | #define KAWETH_PACKET_FILTER_BROADCAST 0x08 |
67 | #define KAWETH_PACKET_FILTER_MULTICAST 0x10 |
68 | |
69 | /* Table 7 */ |
70 | #define KAWETH_COMMAND_GET_ETHERNET_DESC 0x00 |
71 | #define KAWETH_COMMAND_MULTICAST_FILTERS 0x01 |
72 | #define KAWETH_COMMAND_SET_PACKET_FILTER 0x02 |
73 | #define KAWETH_COMMAND_STATISTICS 0x03 |
74 | #define KAWETH_COMMAND_SET_TEMP_MAC 0x06 |
75 | #define KAWETH_COMMAND_GET_TEMP_MAC 0x07 |
76 | #define KAWETH_COMMAND_SET_URB_SIZE 0x08 |
77 | #define KAWETH_COMMAND_SET_SOFS_WAIT 0x09 |
78 | #define KAWETH_COMMAND_SCAN 0xFF |
79 | |
80 | #define KAWETH_SOFS_TO_WAIT 0x05 |
81 | |
82 | #define INTBUFFERSIZE 4 |
83 | |
84 | #define STATE_OFFSET 0 |
85 | #define STATE_MASK 0x40 |
86 | #define STATE_SHIFT 5 |
87 | |
88 | #define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED) |
89 | |
90 | |
91 | MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>" ); |
92 | MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver" ); |
93 | MODULE_LICENSE("GPL" ); |
94 | MODULE_FIRMWARE("kaweth/new_code.bin" ); |
95 | MODULE_FIRMWARE("kaweth/new_code_fix.bin" ); |
96 | MODULE_FIRMWARE("kaweth/trigger_code.bin" ); |
97 | MODULE_FIRMWARE("kaweth/trigger_code_fix.bin" ); |
98 | |
99 | static const char driver_name[] = "kaweth" ; |
100 | |
101 | static int kaweth_probe( |
102 | struct usb_interface *intf, |
103 | const struct usb_device_id *id /* from id_table */ |
104 | ); |
105 | static void kaweth_disconnect(struct usb_interface *intf); |
106 | static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); |
107 | static int kaweth_resume(struct usb_interface *intf); |
108 | |
109 | /**************************************************************** |
110 | * usb_device_id |
111 | ****************************************************************/ |
112 | static const struct usb_device_id usb_klsi_table[] = { |
113 | { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */ |
114 | { USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */ |
115 | { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */ |
116 | { USB_DEVICE(0x0506, 0x11f8) }, /* 3Com 3C460 */ |
117 | { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */ |
118 | { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */ |
119 | { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */ |
120 | { USB_DEVICE(0x0565, 0x0003) }, /* Optus@Home UEP1045A */ |
121 | { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */ |
122 | { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */ |
123 | { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */ |
124 | { USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */ |
125 | { USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */ |
126 | { USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */ |
127 | { USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */ |
128 | { USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */ |
129 | { USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */ |
130 | { USB_DEVICE(0x07c9, 0xb010) }, /* Allied Telesyn AT-USB10 USB Ethernet Adapter */ |
131 | { USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */ |
132 | { USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */ |
133 | { USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */ |
134 | { USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */ |
135 | { USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */ |
136 | { USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */ |
137 | { USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */ |
138 | { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */ |
139 | { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */ |
140 | { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */ |
141 | { USB_DEVICE(0x1485, 0x0001) }, /* Silicom U2E */ |
142 | { USB_DEVICE(0x1485, 0x0002) }, /* Psion Dacom Gold Port Ethernet */ |
143 | { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ |
144 | { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ |
145 | { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ |
146 | { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */ |
147 | { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */ |
148 | {} /* Null terminator */ |
149 | }; |
150 | |
151 | MODULE_DEVICE_TABLE (usb, usb_klsi_table); |
152 | |
153 | /**************************************************************** |
154 | * kaweth_driver |
155 | ****************************************************************/ |
156 | static struct usb_driver kaweth_driver = { |
157 | .name = driver_name, |
158 | .probe = kaweth_probe, |
159 | .disconnect = kaweth_disconnect, |
160 | .suspend = kaweth_suspend, |
161 | .resume = kaweth_resume, |
162 | .id_table = usb_klsi_table, |
163 | .supports_autosuspend = 1, |
164 | .disable_hub_initiated_lpm = 1, |
165 | }; |
166 | |
167 | typedef __u8 eth_addr_t[6]; |
168 | |
169 | /**************************************************************** |
170 | * usb_eth_dev |
171 | ****************************************************************/ |
172 | struct usb_eth_dev { |
173 | char *name; |
174 | __u16 vendor; |
175 | __u16 device; |
176 | void *pdata; |
177 | }; |
178 | |
179 | /**************************************************************** |
180 | * kaweth_ethernet_configuration |
181 | * Refer Table 8 |
182 | ****************************************************************/ |
183 | struct kaweth_ethernet_configuration |
184 | { |
185 | __u8 size; |
186 | __u8 reserved1; |
187 | __u8 reserved2; |
188 | eth_addr_t hw_addr; |
189 | __u32 statistics_mask; |
190 | __le16 segment_size; |
191 | __u16 max_multicast_filters; |
192 | __u8 reserved3; |
193 | } __packed; |
194 | |
195 | /**************************************************************** |
196 | * kaweth_device |
197 | ****************************************************************/ |
198 | struct kaweth_device |
199 | { |
200 | spinlock_t device_lock; |
201 | |
202 | __u32 status; |
203 | int end; |
204 | int suspend_lowmem_rx; |
205 | int suspend_lowmem_ctrl; |
206 | int linkstate; |
207 | int opened; |
208 | struct delayed_work lowmem_work; |
209 | |
210 | struct usb_device *dev; |
211 | struct usb_interface *intf; |
212 | struct net_device *net; |
213 | wait_queue_head_t term_wait; |
214 | |
215 | struct urb *rx_urb; |
216 | struct urb *tx_urb; |
217 | struct urb *irq_urb; |
218 | |
219 | dma_addr_t intbufferhandle; |
220 | __u8 *intbuffer; |
221 | dma_addr_t rxbufferhandle; |
222 | __u8 *rx_buf; |
223 | |
224 | |
225 | struct sk_buff *tx_skb; |
226 | |
227 | __u8 *firmware_buf; |
228 | __u8 scratch[KAWETH_SCRATCH_SIZE]; |
229 | __u16 packet_filter_bitmap; |
230 | |
231 | struct kaweth_ethernet_configuration configuration; |
232 | }; |
233 | |
234 | /**************************************************************** |
235 | * kaweth_read_configuration |
236 | ****************************************************************/ |
237 | static int kaweth_read_configuration(struct kaweth_device *kaweth) |
238 | { |
239 | return usb_control_msg(dev: kaweth->dev, usb_rcvctrlpipe(kaweth->dev, 0), |
240 | KAWETH_COMMAND_GET_ETHERNET_DESC, |
241 | USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, |
242 | value: 0, index: 0, |
243 | data: &kaweth->configuration, |
244 | size: sizeof(kaweth->configuration), |
245 | KAWETH_CONTROL_TIMEOUT); |
246 | } |
247 | |
248 | /**************************************************************** |
249 | * kaweth_set_urb_size |
250 | ****************************************************************/ |
251 | static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) |
252 | { |
253 | netdev_dbg(kaweth->net, "Setting URB size to %d\n" , (unsigned)urb_size); |
254 | |
255 | return usb_control_msg(dev: kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
256 | KAWETH_COMMAND_SET_URB_SIZE, |
257 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
258 | value: urb_size, index: 0, |
259 | data: &kaweth->scratch, size: 0, |
260 | KAWETH_CONTROL_TIMEOUT); |
261 | } |
262 | |
263 | /**************************************************************** |
264 | * kaweth_set_sofs_wait |
265 | ****************************************************************/ |
266 | static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) |
267 | { |
268 | netdev_dbg(kaweth->net, "Set SOFS wait to %d\n" , (unsigned)sofs_wait); |
269 | |
270 | return usb_control_msg(dev: kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
271 | KAWETH_COMMAND_SET_SOFS_WAIT, |
272 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
273 | value: sofs_wait, index: 0, |
274 | data: &kaweth->scratch, size: 0, |
275 | KAWETH_CONTROL_TIMEOUT); |
276 | } |
277 | |
278 | /**************************************************************** |
279 | * kaweth_set_receive_filter |
280 | ****************************************************************/ |
281 | static int kaweth_set_receive_filter(struct kaweth_device *kaweth, |
282 | __u16 receive_filter) |
283 | { |
284 | netdev_dbg(kaweth->net, "Set receive filter to %d\n" , |
285 | (unsigned)receive_filter); |
286 | |
287 | return usb_control_msg(dev: kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
288 | KAWETH_COMMAND_SET_PACKET_FILTER, |
289 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
290 | value: receive_filter, index: 0, |
291 | data: &kaweth->scratch, size: 0, |
292 | KAWETH_CONTROL_TIMEOUT); |
293 | } |
294 | |
295 | /**************************************************************** |
296 | * kaweth_download_firmware |
297 | ****************************************************************/ |
298 | static int kaweth_download_firmware(struct kaweth_device *kaweth, |
299 | const char *fwname, |
300 | __u8 interrupt, |
301 | __u8 type) |
302 | { |
303 | const struct firmware *fw; |
304 | int data_len; |
305 | int ret; |
306 | |
307 | ret = request_firmware(fw: &fw, name: fwname, device: &kaweth->dev->dev); |
308 | if (ret) { |
309 | dev_err(&kaweth->intf->dev, "Firmware request failed\n" ); |
310 | return ret; |
311 | } |
312 | |
313 | if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) { |
314 | dev_err(&kaweth->intf->dev, "Firmware too big: %zu\n" , |
315 | fw->size); |
316 | release_firmware(fw); |
317 | return -ENOSPC; |
318 | } |
319 | data_len = fw->size; |
320 | memcpy(kaweth->firmware_buf, fw->data, fw->size); |
321 | |
322 | release_firmware(fw); |
323 | |
324 | kaweth->firmware_buf[2] = (data_len & 0xFF) - 7; |
325 | kaweth->firmware_buf[3] = data_len >> 8; |
326 | kaweth->firmware_buf[4] = type; |
327 | kaweth->firmware_buf[5] = interrupt; |
328 | |
329 | netdev_dbg(kaweth->net, "High: %i, Low:%i\n" , kaweth->firmware_buf[3], |
330 | kaweth->firmware_buf[2]); |
331 | |
332 | netdev_dbg(kaweth->net, |
333 | "Downloading firmware at %p to kaweth device at %p\n" , |
334 | kaweth->firmware_buf, kaweth); |
335 | netdev_dbg(kaweth->net, "Firmware length: %d\n" , data_len); |
336 | |
337 | return usb_control_msg(dev: kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
338 | KAWETH_COMMAND_SCAN, |
339 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
340 | value: 0, index: 0, |
341 | data: kaweth->firmware_buf, size: data_len, |
342 | KAWETH_CONTROL_TIMEOUT); |
343 | } |
344 | |
345 | /**************************************************************** |
346 | * kaweth_trigger_firmware |
347 | ****************************************************************/ |
348 | static int kaweth_trigger_firmware(struct kaweth_device *kaweth, |
349 | __u8 interrupt) |
350 | { |
351 | kaweth->firmware_buf[0] = 0xB6; |
352 | kaweth->firmware_buf[1] = 0xC3; |
353 | kaweth->firmware_buf[2] = 0x01; |
354 | kaweth->firmware_buf[3] = 0x00; |
355 | kaweth->firmware_buf[4] = 0x06; |
356 | kaweth->firmware_buf[5] = interrupt; |
357 | kaweth->firmware_buf[6] = 0x00; |
358 | kaweth->firmware_buf[7] = 0x00; |
359 | |
360 | return usb_control_msg(dev: kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
361 | KAWETH_COMMAND_SCAN, |
362 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
363 | value: 0, index: 0, |
364 | data: (void *)kaweth->firmware_buf, size: 8, |
365 | KAWETH_CONTROL_TIMEOUT); |
366 | } |
367 | |
368 | /**************************************************************** |
369 | * kaweth_reset |
370 | ****************************************************************/ |
371 | static int kaweth_reset(struct kaweth_device *kaweth) |
372 | { |
373 | int result; |
374 | |
375 | result = usb_reset_configuration(dev: kaweth->dev); |
376 | mdelay(10); |
377 | |
378 | netdev_dbg(kaweth->net, "kaweth_reset() returns %d.\n" , result); |
379 | |
380 | return result; |
381 | } |
382 | |
383 | static void kaweth_usb_receive(struct urb *); |
384 | static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t); |
385 | |
386 | /**************************************************************** |
387 | int_callback |
388 | *****************************************************************/ |
389 | |
390 | static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf) |
391 | { |
392 | int status; |
393 | |
394 | status = usb_submit_urb (urb: kaweth->irq_urb, mem_flags: mf); |
395 | if (unlikely(status == -ENOMEM)) { |
396 | kaweth->suspend_lowmem_ctrl = 1; |
397 | schedule_delayed_work(dwork: &kaweth->lowmem_work, HZ/4); |
398 | } else { |
399 | kaweth->suspend_lowmem_ctrl = 0; |
400 | } |
401 | |
402 | if (status) |
403 | dev_err(&kaweth->intf->dev, |
404 | "can't resubmit intr, %s-%s, status %d\n" , |
405 | kaweth->dev->bus->bus_name, |
406 | kaweth->dev->devpath, status); |
407 | } |
408 | |
409 | static void int_callback(struct urb *u) |
410 | { |
411 | struct kaweth_device *kaweth = u->context; |
412 | int act_state; |
413 | int status = u->status; |
414 | |
415 | switch (status) { |
416 | case 0: /* success */ |
417 | break; |
418 | case -ECONNRESET: /* unlink */ |
419 | case -ENOENT: |
420 | case -ESHUTDOWN: |
421 | return; |
422 | /* -EPIPE: should clear the halt */ |
423 | default: /* error */ |
424 | goto resubmit; |
425 | } |
426 | |
427 | /* we check the link state to report changes */ |
428 | if (kaweth->linkstate != (act_state = ( kaweth->intbuffer[STATE_OFFSET] | STATE_MASK) >> STATE_SHIFT)) { |
429 | if (act_state) |
430 | netif_carrier_on(dev: kaweth->net); |
431 | else |
432 | netif_carrier_off(dev: kaweth->net); |
433 | |
434 | kaweth->linkstate = act_state; |
435 | } |
436 | resubmit: |
437 | kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC); |
438 | } |
439 | |
440 | static void kaweth_resubmit_tl(struct work_struct *work) |
441 | { |
442 | struct kaweth_device *kaweth = |
443 | container_of(work, struct kaweth_device, lowmem_work.work); |
444 | |
445 | if (IS_BLOCKED(kaweth->status)) |
446 | return; |
447 | |
448 | if (kaweth->suspend_lowmem_rx) |
449 | kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); |
450 | |
451 | if (kaweth->suspend_lowmem_ctrl) |
452 | kaweth_resubmit_int_urb(kaweth, GFP_NOIO); |
453 | } |
454 | |
455 | |
456 | /**************************************************************** |
457 | * kaweth_resubmit_rx_urb |
458 | ****************************************************************/ |
459 | static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, |
460 | gfp_t mem_flags) |
461 | { |
462 | int result; |
463 | |
464 | usb_fill_bulk_urb(urb: kaweth->rx_urb, |
465 | dev: kaweth->dev, |
466 | usb_rcvbulkpipe(kaweth->dev, 1), |
467 | transfer_buffer: kaweth->rx_buf, |
468 | KAWETH_BUF_SIZE, |
469 | complete_fn: kaweth_usb_receive, |
470 | context: kaweth); |
471 | kaweth->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
472 | kaweth->rx_urb->transfer_dma = kaweth->rxbufferhandle; |
473 | |
474 | if((result = usb_submit_urb(urb: kaweth->rx_urb, mem_flags))) { |
475 | if (result == -ENOMEM) { |
476 | kaweth->suspend_lowmem_rx = 1; |
477 | schedule_delayed_work(dwork: &kaweth->lowmem_work, HZ/4); |
478 | } |
479 | dev_err(&kaweth->intf->dev, "resubmitting rx_urb %d failed\n" , |
480 | result); |
481 | } else { |
482 | kaweth->suspend_lowmem_rx = 0; |
483 | } |
484 | |
485 | return result; |
486 | } |
487 | |
488 | static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth, |
489 | bool may_sleep); |
490 | |
491 | /**************************************************************** |
492 | * kaweth_usb_receive |
493 | ****************************************************************/ |
494 | static void kaweth_usb_receive(struct urb *urb) |
495 | { |
496 | struct device *dev = &urb->dev->dev; |
497 | struct kaweth_device *kaweth = urb->context; |
498 | struct net_device *net = kaweth->net; |
499 | int status = urb->status; |
500 | unsigned long flags; |
501 | int count = urb->actual_length; |
502 | int count2 = urb->transfer_buffer_length; |
503 | |
504 | __u16 pkt_len = le16_to_cpup(p: (__le16 *)kaweth->rx_buf); |
505 | |
506 | struct sk_buff *skb; |
507 | |
508 | if (unlikely(status == -EPIPE)) { |
509 | net->stats.rx_errors++; |
510 | kaweth->end = 1; |
511 | wake_up(&kaweth->term_wait); |
512 | dev_dbg(dev, "Status was -EPIPE.\n" ); |
513 | return; |
514 | } |
515 | if (unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) { |
516 | /* we are killed - set a flag and wake the disconnect handler */ |
517 | kaweth->end = 1; |
518 | wake_up(&kaweth->term_wait); |
519 | dev_dbg(dev, "Status was -ECONNRESET or -ESHUTDOWN.\n" ); |
520 | return; |
521 | } |
522 | if (unlikely(status == -EPROTO || status == -ETIME || |
523 | status == -EILSEQ)) { |
524 | net->stats.rx_errors++; |
525 | dev_dbg(dev, "Status was -EPROTO, -ETIME, or -EILSEQ.\n" ); |
526 | return; |
527 | } |
528 | if (unlikely(status == -EOVERFLOW)) { |
529 | net->stats.rx_errors++; |
530 | dev_dbg(dev, "Status was -EOVERFLOW.\n" ); |
531 | } |
532 | spin_lock_irqsave(&kaweth->device_lock, flags); |
533 | if (IS_BLOCKED(kaweth->status)) { |
534 | spin_unlock_irqrestore(lock: &kaweth->device_lock, flags); |
535 | return; |
536 | } |
537 | spin_unlock_irqrestore(lock: &kaweth->device_lock, flags); |
538 | |
539 | if(status && status != -EREMOTEIO && count != 1) { |
540 | dev_err(&kaweth->intf->dev, |
541 | "%s RX status: %d count: %d packet_len: %d\n" , |
542 | net->name, status, count, (int)pkt_len); |
543 | kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); |
544 | return; |
545 | } |
546 | |
547 | if(kaweth->net && (count > 2)) { |
548 | if(pkt_len > (count - 2)) { |
549 | dev_err(&kaweth->intf->dev, |
550 | "Packet length too long for USB frame (pkt_len: %x, count: %x)\n" , |
551 | pkt_len, count); |
552 | dev_err(&kaweth->intf->dev, "Packet len & 2047: %x\n" , |
553 | pkt_len & 2047); |
554 | dev_err(&kaweth->intf->dev, "Count 2: %x\n" , count2); |
555 | kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); |
556 | return; |
557 | } |
558 | |
559 | if(!(skb = dev_alloc_skb(length: pkt_len+2))) { |
560 | kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); |
561 | return; |
562 | } |
563 | |
564 | skb_reserve(skb, len: 2); /* Align IP on 16 byte boundaries */ |
565 | |
566 | skb_copy_to_linear_data(skb, from: kaweth->rx_buf + 2, len: pkt_len); |
567 | |
568 | skb_put(skb, len: pkt_len); |
569 | |
570 | skb->protocol = eth_type_trans(skb, dev: net); |
571 | |
572 | netif_rx(skb); |
573 | |
574 | net->stats.rx_packets++; |
575 | net->stats.rx_bytes += pkt_len; |
576 | } |
577 | |
578 | kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); |
579 | } |
580 | |
581 | /**************************************************************** |
582 | * kaweth_open |
583 | ****************************************************************/ |
584 | static int kaweth_open(struct net_device *net) |
585 | { |
586 | struct kaweth_device *kaweth = netdev_priv(dev: net); |
587 | int res; |
588 | |
589 | res = usb_autopm_get_interface(intf: kaweth->intf); |
590 | if (res) { |
591 | dev_err(&kaweth->intf->dev, "Interface cannot be resumed.\n" ); |
592 | return -EIO; |
593 | } |
594 | res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); |
595 | if (res) |
596 | goto err_out; |
597 | |
598 | usb_fill_int_urb( |
599 | urb: kaweth->irq_urb, |
600 | dev: kaweth->dev, |
601 | usb_rcvintpipe(kaweth->dev, 3), |
602 | transfer_buffer: kaweth->intbuffer, |
603 | INTBUFFERSIZE, |
604 | complete_fn: int_callback, |
605 | context: kaweth, |
606 | interval: 250); /* overriding the descriptor */ |
607 | kaweth->irq_urb->transfer_dma = kaweth->intbufferhandle; |
608 | kaweth->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
609 | |
610 | res = usb_submit_urb(urb: kaweth->irq_urb, GFP_KERNEL); |
611 | if (res) { |
612 | usb_kill_urb(urb: kaweth->rx_urb); |
613 | goto err_out; |
614 | } |
615 | kaweth->opened = 1; |
616 | |
617 | netif_start_queue(dev: net); |
618 | |
619 | kaweth_async_set_rx_mode(kaweth, may_sleep: true); |
620 | return 0; |
621 | |
622 | err_out: |
623 | usb_autopm_put_interface(intf: kaweth->intf); |
624 | return -EIO; |
625 | } |
626 | |
627 | /**************************************************************** |
628 | * kaweth_kill_urbs |
629 | ****************************************************************/ |
630 | static void kaweth_kill_urbs(struct kaweth_device *kaweth) |
631 | { |
632 | usb_kill_urb(urb: kaweth->irq_urb); |
633 | usb_kill_urb(urb: kaweth->rx_urb); |
634 | usb_kill_urb(urb: kaweth->tx_urb); |
635 | |
636 | cancel_delayed_work_sync(dwork: &kaweth->lowmem_work); |
637 | |
638 | /* a scheduled work may have resubmitted, |
639 | we hit them again */ |
640 | usb_kill_urb(urb: kaweth->irq_urb); |
641 | usb_kill_urb(urb: kaweth->rx_urb); |
642 | } |
643 | |
644 | /**************************************************************** |
645 | * kaweth_close |
646 | ****************************************************************/ |
647 | static int kaweth_close(struct net_device *net) |
648 | { |
649 | struct kaweth_device *kaweth = netdev_priv(dev: net); |
650 | |
651 | netif_stop_queue(dev: net); |
652 | kaweth->opened = 0; |
653 | |
654 | kaweth->status |= KAWETH_STATUS_CLOSING; |
655 | |
656 | kaweth_kill_urbs(kaweth); |
657 | |
658 | kaweth->status &= ~KAWETH_STATUS_CLOSING; |
659 | |
660 | usb_autopm_put_interface(intf: kaweth->intf); |
661 | |
662 | return 0; |
663 | } |
664 | |
665 | static u32 kaweth_get_link(struct net_device *dev) |
666 | { |
667 | struct kaweth_device *kaweth = netdev_priv(dev); |
668 | |
669 | return kaweth->linkstate; |
670 | } |
671 | |
672 | static const struct ethtool_ops ops = { |
673 | .get_link = kaweth_get_link |
674 | }; |
675 | |
676 | /**************************************************************** |
677 | * kaweth_usb_transmit_complete |
678 | ****************************************************************/ |
679 | static void kaweth_usb_transmit_complete(struct urb *urb) |
680 | { |
681 | struct kaweth_device *kaweth = urb->context; |
682 | struct sk_buff *skb = kaweth->tx_skb; |
683 | int status = urb->status; |
684 | |
685 | if (unlikely(status != 0)) |
686 | if (status != -ENOENT) |
687 | dev_dbg(&urb->dev->dev, "%s: TX status %d.\n" , |
688 | kaweth->net->name, status); |
689 | |
690 | netif_wake_queue(dev: kaweth->net); |
691 | dev_kfree_skb_irq(skb); |
692 | } |
693 | |
694 | /**************************************************************** |
695 | * kaweth_start_xmit |
696 | ****************************************************************/ |
697 | static netdev_tx_t kaweth_start_xmit(struct sk_buff *skb, |
698 | struct net_device *net) |
699 | { |
700 | struct kaweth_device *kaweth = netdev_priv(dev: net); |
701 | __le16 *; |
702 | |
703 | int res; |
704 | |
705 | spin_lock_irq(lock: &kaweth->device_lock); |
706 | |
707 | kaweth_async_set_rx_mode(kaweth, may_sleep: false); |
708 | netif_stop_queue(dev: net); |
709 | if (IS_BLOCKED(kaweth->status)) { |
710 | goto skip; |
711 | } |
712 | |
713 | /* We now decide whether we can put our special header into the sk_buff */ |
714 | if (skb_cow_head(skb, headroom: 2)) { |
715 | net->stats.tx_errors++; |
716 | netif_start_queue(dev: net); |
717 | spin_unlock_irq(lock: &kaweth->device_lock); |
718 | dev_kfree_skb_any(skb); |
719 | return NETDEV_TX_OK; |
720 | } |
721 | |
722 | private_header = __skb_push(skb, len: 2); |
723 | *private_header = cpu_to_le16(skb->len-2); |
724 | kaweth->tx_skb = skb; |
725 | |
726 | usb_fill_bulk_urb(urb: kaweth->tx_urb, |
727 | dev: kaweth->dev, |
728 | usb_sndbulkpipe(kaweth->dev, 2), |
729 | transfer_buffer: private_header, |
730 | buffer_length: skb->len, |
731 | complete_fn: kaweth_usb_transmit_complete, |
732 | context: kaweth); |
733 | kaweth->end = 0; |
734 | |
735 | if((res = usb_submit_urb(urb: kaweth->tx_urb, GFP_ATOMIC))) |
736 | { |
737 | dev_warn(&net->dev, "kaweth failed tx_urb %d\n" , res); |
738 | skip: |
739 | net->stats.tx_errors++; |
740 | |
741 | netif_start_queue(dev: net); |
742 | dev_kfree_skb_irq(skb); |
743 | } |
744 | else |
745 | { |
746 | net->stats.tx_packets++; |
747 | net->stats.tx_bytes += skb->len; |
748 | } |
749 | |
750 | spin_unlock_irq(lock: &kaweth->device_lock); |
751 | |
752 | return NETDEV_TX_OK; |
753 | } |
754 | |
755 | /**************************************************************** |
756 | * kaweth_set_rx_mode |
757 | ****************************************************************/ |
758 | static void kaweth_set_rx_mode(struct net_device *net) |
759 | { |
760 | struct kaweth_device *kaweth = netdev_priv(dev: net); |
761 | |
762 | __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED | |
763 | KAWETH_PACKET_FILTER_BROADCAST | |
764 | KAWETH_PACKET_FILTER_MULTICAST; |
765 | |
766 | netdev_dbg(net, "Setting Rx mode to %d\n" , packet_filter_bitmap); |
767 | |
768 | netif_stop_queue(dev: net); |
769 | |
770 | if (net->flags & IFF_PROMISC) { |
771 | packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS; |
772 | } |
773 | else if (!netdev_mc_empty(net) || (net->flags & IFF_ALLMULTI)) { |
774 | packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST; |
775 | } |
776 | |
777 | kaweth->packet_filter_bitmap = packet_filter_bitmap; |
778 | netif_wake_queue(dev: net); |
779 | } |
780 | |
781 | /**************************************************************** |
782 | * kaweth_async_set_rx_mode |
783 | ****************************************************************/ |
784 | static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth, |
785 | bool may_sleep) |
786 | { |
787 | int ret; |
788 | __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; |
789 | |
790 | kaweth->packet_filter_bitmap = 0; |
791 | if (packet_filter_bitmap == 0) |
792 | return; |
793 | |
794 | if (!may_sleep) |
795 | return; |
796 | |
797 | ret = usb_control_msg(dev: kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
798 | KAWETH_COMMAND_SET_PACKET_FILTER, |
799 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
800 | value: packet_filter_bitmap, index: 0, |
801 | data: &kaweth->scratch, size: 0, |
802 | KAWETH_CONTROL_TIMEOUT); |
803 | if (ret < 0) |
804 | dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n" , |
805 | ret); |
806 | else |
807 | netdev_dbg(kaweth->net, "Set Rx mode to %d\n" , |
808 | packet_filter_bitmap); |
809 | } |
810 | |
811 | /**************************************************************** |
812 | * kaweth_tx_timeout |
813 | ****************************************************************/ |
814 | static void kaweth_tx_timeout(struct net_device *net, unsigned int txqueue) |
815 | { |
816 | struct kaweth_device *kaweth = netdev_priv(dev: net); |
817 | |
818 | dev_warn(&net->dev, "%s: Tx timed out. Resetting.\n" , net->name); |
819 | net->stats.tx_errors++; |
820 | netif_trans_update(dev: net); |
821 | |
822 | usb_unlink_urb(urb: kaweth->tx_urb); |
823 | } |
824 | |
825 | /**************************************************************** |
826 | * kaweth_suspend |
827 | ****************************************************************/ |
828 | static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) |
829 | { |
830 | struct kaweth_device *kaweth = usb_get_intfdata(intf); |
831 | unsigned long flags; |
832 | |
833 | spin_lock_irqsave(&kaweth->device_lock, flags); |
834 | kaweth->status |= KAWETH_STATUS_SUSPENDING; |
835 | spin_unlock_irqrestore(lock: &kaweth->device_lock, flags); |
836 | |
837 | kaweth_kill_urbs(kaweth); |
838 | return 0; |
839 | } |
840 | |
841 | /**************************************************************** |
842 | * kaweth_resume |
843 | ****************************************************************/ |
844 | static int kaweth_resume(struct usb_interface *intf) |
845 | { |
846 | struct kaweth_device *kaweth = usb_get_intfdata(intf); |
847 | unsigned long flags; |
848 | |
849 | spin_lock_irqsave(&kaweth->device_lock, flags); |
850 | kaweth->status &= ~KAWETH_STATUS_SUSPENDING; |
851 | spin_unlock_irqrestore(lock: &kaweth->device_lock, flags); |
852 | |
853 | if (!kaweth->opened) |
854 | return 0; |
855 | kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); |
856 | kaweth_resubmit_int_urb(kaweth, GFP_NOIO); |
857 | |
858 | return 0; |
859 | } |
860 | |
861 | /**************************************************************** |
862 | * kaweth_probe |
863 | ****************************************************************/ |
864 | |
865 | |
866 | static const struct net_device_ops kaweth_netdev_ops = { |
867 | .ndo_open = kaweth_open, |
868 | .ndo_stop = kaweth_close, |
869 | .ndo_start_xmit = kaweth_start_xmit, |
870 | .ndo_tx_timeout = kaweth_tx_timeout, |
871 | .ndo_set_rx_mode = kaweth_set_rx_mode, |
872 | .ndo_set_mac_address = eth_mac_addr, |
873 | .ndo_validate_addr = eth_validate_addr, |
874 | }; |
875 | |
876 | static int kaweth_probe( |
877 | struct usb_interface *intf, |
878 | const struct usb_device_id *id /* from id_table */ |
879 | ) |
880 | { |
881 | struct device *dev = &intf->dev; |
882 | struct usb_device *udev = interface_to_usbdev(intf); |
883 | struct kaweth_device *kaweth; |
884 | struct net_device *netdev; |
885 | const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
886 | int result = 0; |
887 | int rv = -EIO; |
888 | |
889 | dev_dbg(dev, |
890 | "Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x\n" , |
891 | udev->devnum, le16_to_cpu(udev->descriptor.idVendor), |
892 | le16_to_cpu(udev->descriptor.idProduct), |
893 | le16_to_cpu(udev->descriptor.bcdDevice)); |
894 | |
895 | dev_dbg(dev, "Device at %p\n" , udev); |
896 | |
897 | dev_dbg(dev, "Descriptor length: %x type: %x\n" , |
898 | (int)udev->descriptor.bLength, |
899 | (int)udev->descriptor.bDescriptorType); |
900 | |
901 | netdev = alloc_etherdev(sizeof(*kaweth)); |
902 | if (!netdev) |
903 | return -ENOMEM; |
904 | |
905 | kaweth = netdev_priv(dev: netdev); |
906 | kaweth->dev = udev; |
907 | kaweth->net = netdev; |
908 | kaweth->intf = intf; |
909 | |
910 | spin_lock_init(&kaweth->device_lock); |
911 | init_waitqueue_head(&kaweth->term_wait); |
912 | |
913 | dev_dbg(dev, "Resetting.\n" ); |
914 | |
915 | kaweth_reset(kaweth); |
916 | |
917 | /* |
918 | * If high byte of bcdDevice is nonzero, firmware is already |
919 | * downloaded. Don't try to do it again, or we'll hang the device. |
920 | */ |
921 | |
922 | if (le16_to_cpu(udev->descriptor.bcdDevice) >> 8) { |
923 | dev_info(dev, "Firmware present in device.\n" ); |
924 | } else { |
925 | /* Download the firmware */ |
926 | dev_info(dev, "Downloading firmware...\n" ); |
927 | kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); |
928 | if (!kaweth->firmware_buf) { |
929 | rv = -ENOMEM; |
930 | goto err_free_netdev; |
931 | } |
932 | if ((result = kaweth_download_firmware(kaweth, |
933 | fwname: "kaweth/new_code.bin" , |
934 | interrupt: 100, |
935 | type: 2)) < 0) { |
936 | dev_err(dev, "Error downloading firmware (%d)\n" , |
937 | result); |
938 | goto err_fw; |
939 | } |
940 | |
941 | if ((result = kaweth_download_firmware(kaweth, |
942 | fwname: "kaweth/new_code_fix.bin" , |
943 | interrupt: 100, |
944 | type: 3)) < 0) { |
945 | dev_err(dev, "Error downloading firmware fix (%d)\n" , |
946 | result); |
947 | goto err_fw; |
948 | } |
949 | |
950 | if ((result = kaweth_download_firmware(kaweth, |
951 | fwname: "kaweth/trigger_code.bin" , |
952 | interrupt: 126, |
953 | type: 2)) < 0) { |
954 | dev_err(dev, "Error downloading trigger code (%d)\n" , |
955 | result); |
956 | goto err_fw; |
957 | |
958 | } |
959 | |
960 | if ((result = kaweth_download_firmware(kaweth, |
961 | fwname: "kaweth/trigger_code_fix.bin" , |
962 | interrupt: 126, |
963 | type: 3)) < 0) { |
964 | dev_err(dev, "Error downloading trigger code fix (%d)\n" , result); |
965 | goto err_fw; |
966 | } |
967 | |
968 | |
969 | if ((result = kaweth_trigger_firmware(kaweth, interrupt: 126)) < 0) { |
970 | dev_err(dev, "Error triggering firmware (%d)\n" , result); |
971 | goto err_fw; |
972 | } |
973 | |
974 | /* Device will now disappear for a moment... */ |
975 | dev_info(dev, "Firmware loaded. I'll be back...\n" ); |
976 | err_fw: |
977 | free_page((unsigned long)kaweth->firmware_buf); |
978 | free_netdev(dev: netdev); |
979 | return -EIO; |
980 | } |
981 | |
982 | result = kaweth_read_configuration(kaweth); |
983 | |
984 | if(result < 0) { |
985 | dev_err(dev, "Error reading configuration (%d), no net device created\n" , result); |
986 | goto err_free_netdev; |
987 | } |
988 | |
989 | dev_info(dev, "Statistics collection: %x\n" , kaweth->configuration.statistics_mask); |
990 | dev_info(dev, "Multicast filter limit: %x\n" , kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); |
991 | dev_info(dev, "MTU: %d\n" , le16_to_cpu(kaweth->configuration.segment_size)); |
992 | dev_info(dev, "Read MAC address %pM\n" , kaweth->configuration.hw_addr); |
993 | |
994 | if(!memcmp(p: &kaweth->configuration.hw_addr, |
995 | q: &bcast_addr, |
996 | size: sizeof(bcast_addr))) { |
997 | dev_err(dev, "Firmware not functioning properly, no net device created\n" ); |
998 | goto err_free_netdev; |
999 | } |
1000 | |
1001 | if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { |
1002 | dev_dbg(dev, "Error setting URB size\n" ); |
1003 | goto err_free_netdev; |
1004 | } |
1005 | |
1006 | if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { |
1007 | dev_err(dev, "Error setting SOFS wait\n" ); |
1008 | goto err_free_netdev; |
1009 | } |
1010 | |
1011 | result = kaweth_set_receive_filter(kaweth, |
1012 | KAWETH_PACKET_FILTER_DIRECTED | |
1013 | KAWETH_PACKET_FILTER_BROADCAST | |
1014 | KAWETH_PACKET_FILTER_MULTICAST); |
1015 | |
1016 | if(result < 0) { |
1017 | dev_err(dev, "Error setting receive filter\n" ); |
1018 | goto err_free_netdev; |
1019 | } |
1020 | |
1021 | dev_dbg(dev, "Initializing net device.\n" ); |
1022 | |
1023 | kaweth->tx_urb = usb_alloc_urb(iso_packets: 0, GFP_KERNEL); |
1024 | if (!kaweth->tx_urb) |
1025 | goto err_free_netdev; |
1026 | kaweth->rx_urb = usb_alloc_urb(iso_packets: 0, GFP_KERNEL); |
1027 | if (!kaweth->rx_urb) |
1028 | goto err_only_tx; |
1029 | kaweth->irq_urb = usb_alloc_urb(iso_packets: 0, GFP_KERNEL); |
1030 | if (!kaweth->irq_urb) |
1031 | goto err_tx_and_rx; |
1032 | |
1033 | kaweth->intbuffer = usb_alloc_coherent( dev: kaweth->dev, |
1034 | INTBUFFERSIZE, |
1035 | GFP_KERNEL, |
1036 | dma: &kaweth->intbufferhandle); |
1037 | if (!kaweth->intbuffer) |
1038 | goto err_tx_and_rx_and_irq; |
1039 | kaweth->rx_buf = usb_alloc_coherent( dev: kaweth->dev, |
1040 | KAWETH_BUF_SIZE, |
1041 | GFP_KERNEL, |
1042 | dma: &kaweth->rxbufferhandle); |
1043 | if (!kaweth->rx_buf) |
1044 | goto err_all_but_rxbuf; |
1045 | |
1046 | memcpy(netdev->broadcast, &bcast_addr, sizeof(bcast_addr)); |
1047 | eth_hw_addr_set(dev: netdev, addr: (u8 *)&kaweth->configuration.hw_addr); |
1048 | |
1049 | netdev->netdev_ops = &kaweth_netdev_ops; |
1050 | netdev->watchdog_timeo = KAWETH_TX_TIMEOUT; |
1051 | netdev->mtu = le16_to_cpu(kaweth->configuration.segment_size); |
1052 | netdev->ethtool_ops = &ops; |
1053 | |
1054 | /* kaweth is zeroed as part of alloc_netdev */ |
1055 | INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); |
1056 | usb_set_intfdata(intf, data: kaweth); |
1057 | |
1058 | SET_NETDEV_DEV(netdev, dev); |
1059 | if (register_netdev(dev: netdev) != 0) { |
1060 | dev_err(dev, "Error registering netdev.\n" ); |
1061 | goto err_intfdata; |
1062 | } |
1063 | |
1064 | dev_info(dev, "kaweth interface created at %s\n" , |
1065 | kaweth->net->name); |
1066 | |
1067 | return 0; |
1068 | |
1069 | err_intfdata: |
1070 | usb_set_intfdata(intf, NULL); |
1071 | usb_free_coherent(dev: kaweth->dev, KAWETH_BUF_SIZE, addr: (void *)kaweth->rx_buf, dma: kaweth->rxbufferhandle); |
1072 | err_all_but_rxbuf: |
1073 | usb_free_coherent(dev: kaweth->dev, INTBUFFERSIZE, addr: (void *)kaweth->intbuffer, dma: kaweth->intbufferhandle); |
1074 | err_tx_and_rx_and_irq: |
1075 | usb_free_urb(urb: kaweth->irq_urb); |
1076 | err_tx_and_rx: |
1077 | usb_free_urb(urb: kaweth->rx_urb); |
1078 | err_only_tx: |
1079 | usb_free_urb(urb: kaweth->tx_urb); |
1080 | err_free_netdev: |
1081 | free_netdev(dev: netdev); |
1082 | |
1083 | return rv; |
1084 | } |
1085 | |
1086 | /**************************************************************** |
1087 | * kaweth_disconnect |
1088 | ****************************************************************/ |
1089 | static void kaweth_disconnect(struct usb_interface *intf) |
1090 | { |
1091 | struct kaweth_device *kaweth = usb_get_intfdata(intf); |
1092 | struct net_device *netdev; |
1093 | |
1094 | usb_set_intfdata(intf, NULL); |
1095 | if (!kaweth) { |
1096 | dev_warn(&intf->dev, "unregistering non-existent device\n" ); |
1097 | return; |
1098 | } |
1099 | netdev = kaweth->net; |
1100 | |
1101 | netdev_dbg(kaweth->net, "Unregistering net device\n" ); |
1102 | unregister_netdev(dev: netdev); |
1103 | |
1104 | usb_free_urb(urb: kaweth->rx_urb); |
1105 | usb_free_urb(urb: kaweth->tx_urb); |
1106 | usb_free_urb(urb: kaweth->irq_urb); |
1107 | |
1108 | usb_free_coherent(dev: kaweth->dev, KAWETH_BUF_SIZE, addr: (void *)kaweth->rx_buf, dma: kaweth->rxbufferhandle); |
1109 | usb_free_coherent(dev: kaweth->dev, INTBUFFERSIZE, addr: (void *)kaweth->intbuffer, dma: kaweth->intbufferhandle); |
1110 | |
1111 | free_netdev(dev: netdev); |
1112 | } |
1113 | |
1114 | |
1115 | module_usb_driver(kaweth_driver); |
1116 | |