1 | /* |
2 | * ipheth.c - Apple iPhone USB Ethernet driver |
3 | * |
4 | * Copyright (c) 2009 Diego Giagio <diego@giagio.com> |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of GIAGIO.COM nor the names of its contributors |
16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. |
18 | * |
19 | * Alternatively, provided that this notice is retained in full, this |
20 | * software may be distributed under the terms of the GNU General |
21 | * Public License ("GPL") version 2, in which case the provisions of the |
22 | * GPL apply INSTEAD OF those given above. |
23 | * |
24 | * The provided data structures and external interfaces from this code |
25 | * are not restricted to be used by modules with a GPL compatible license. |
26 | * |
27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
32 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
33 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
34 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
35 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
36 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
37 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
38 | * DAMAGE. |
39 | * |
40 | * |
41 | * Attention: iPhone device must be paired, otherwise it won't respond to our |
42 | * driver. For more info: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver |
43 | * |
44 | */ |
45 | |
46 | #include <linux/kernel.h> |
47 | #include <linux/errno.h> |
48 | #include <linux/slab.h> |
49 | #include <linux/module.h> |
50 | #include <linux/netdevice.h> |
51 | #include <linux/etherdevice.h> |
52 | #include <linux/ethtool.h> |
53 | #include <linux/usb.h> |
54 | #include <linux/workqueue.h> |
55 | #include <linux/usb/cdc.h> |
56 | |
57 | #define USB_VENDOR_APPLE 0x05ac |
58 | |
59 | #define IPHETH_USBINTF_CLASS 255 |
60 | #define IPHETH_USBINTF_SUBCLASS 253 |
61 | #define IPHETH_USBINTF_PROTO 1 |
62 | |
63 | #define IPHETH_IP_ALIGN 2 /* padding at front of URB */ |
64 | #define (12 + 96) /* NCMH + NCM0 */ |
65 | #define IPHETH_TX_BUF_SIZE ETH_FRAME_LEN |
66 | #define IPHETH_RX_BUF_SIZE_LEGACY (IPHETH_IP_ALIGN + ETH_FRAME_LEN) |
67 | #define IPHETH_RX_BUF_SIZE_NCM 65536 |
68 | |
69 | #define IPHETH_TX_TIMEOUT (5 * HZ) |
70 | |
71 | #define IPHETH_INTFNUM 2 |
72 | #define IPHETH_ALT_INTFNUM 1 |
73 | |
74 | #define IPHETH_CTRL_ENDP 0x00 |
75 | #define IPHETH_CTRL_BUF_SIZE 0x40 |
76 | #define IPHETH_CTRL_TIMEOUT (5 * HZ) |
77 | |
78 | #define IPHETH_CMD_GET_MACADDR 0x00 |
79 | #define IPHETH_CMD_ENABLE_NCM 0x04 |
80 | #define IPHETH_CMD_CARRIER_CHECK 0x45 |
81 | |
82 | #define IPHETH_CARRIER_CHECK_TIMEOUT round_jiffies_relative(1 * HZ) |
83 | #define IPHETH_CARRIER_ON 0x04 |
84 | |
85 | static const struct usb_device_id ipheth_table[] = { |
86 | { USB_VENDOR_AND_INTERFACE_INFO(USB_VENDOR_APPLE, IPHETH_USBINTF_CLASS, |
87 | IPHETH_USBINTF_SUBCLASS, |
88 | IPHETH_USBINTF_PROTO) }, |
89 | { } |
90 | }; |
91 | MODULE_DEVICE_TABLE(usb, ipheth_table); |
92 | |
93 | struct ipheth_device { |
94 | struct usb_device *udev; |
95 | struct usb_interface *intf; |
96 | struct net_device *net; |
97 | struct urb *tx_urb; |
98 | struct urb *rx_urb; |
99 | unsigned char *tx_buf; |
100 | unsigned char *rx_buf; |
101 | unsigned char *ctrl_buf; |
102 | u8 bulk_in; |
103 | u8 bulk_out; |
104 | struct delayed_work carrier_work; |
105 | bool confirmed_pairing; |
106 | int (*rcvbulk_callback)(struct urb *urb); |
107 | size_t rx_buf_len; |
108 | }; |
109 | |
110 | static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags); |
111 | |
112 | static int ipheth_alloc_urbs(struct ipheth_device *iphone) |
113 | { |
114 | struct urb *tx_urb = NULL; |
115 | struct urb *rx_urb = NULL; |
116 | u8 *tx_buf = NULL; |
117 | u8 *rx_buf = NULL; |
118 | |
119 | tx_urb = usb_alloc_urb(iso_packets: 0, GFP_KERNEL); |
120 | if (tx_urb == NULL) |
121 | goto error_nomem; |
122 | |
123 | rx_urb = usb_alloc_urb(iso_packets: 0, GFP_KERNEL); |
124 | if (rx_urb == NULL) |
125 | goto free_tx_urb; |
126 | |
127 | tx_buf = usb_alloc_coherent(dev: iphone->udev, IPHETH_TX_BUF_SIZE, |
128 | GFP_KERNEL, dma: &tx_urb->transfer_dma); |
129 | if (tx_buf == NULL) |
130 | goto free_rx_urb; |
131 | |
132 | rx_buf = usb_alloc_coherent(dev: iphone->udev, size: iphone->rx_buf_len, |
133 | GFP_KERNEL, dma: &rx_urb->transfer_dma); |
134 | if (rx_buf == NULL) |
135 | goto free_tx_buf; |
136 | |
137 | |
138 | iphone->tx_urb = tx_urb; |
139 | iphone->rx_urb = rx_urb; |
140 | iphone->tx_buf = tx_buf; |
141 | iphone->rx_buf = rx_buf; |
142 | return 0; |
143 | |
144 | free_tx_buf: |
145 | usb_free_coherent(dev: iphone->udev, IPHETH_TX_BUF_SIZE, addr: tx_buf, |
146 | dma: tx_urb->transfer_dma); |
147 | free_rx_urb: |
148 | usb_free_urb(urb: rx_urb); |
149 | free_tx_urb: |
150 | usb_free_urb(urb: tx_urb); |
151 | error_nomem: |
152 | return -ENOMEM; |
153 | } |
154 | |
155 | static void ipheth_free_urbs(struct ipheth_device *iphone) |
156 | { |
157 | usb_free_coherent(dev: iphone->udev, size: iphone->rx_buf_len, addr: iphone->rx_buf, |
158 | dma: iphone->rx_urb->transfer_dma); |
159 | usb_free_coherent(dev: iphone->udev, IPHETH_TX_BUF_SIZE, addr: iphone->tx_buf, |
160 | dma: iphone->tx_urb->transfer_dma); |
161 | usb_free_urb(urb: iphone->rx_urb); |
162 | usb_free_urb(urb: iphone->tx_urb); |
163 | } |
164 | |
165 | static void ipheth_kill_urbs(struct ipheth_device *dev) |
166 | { |
167 | usb_kill_urb(urb: dev->tx_urb); |
168 | usb_kill_urb(urb: dev->rx_urb); |
169 | } |
170 | |
171 | static int ipheth_consume_skb(char *buf, int len, struct ipheth_device *dev) |
172 | { |
173 | struct sk_buff *skb; |
174 | |
175 | skb = dev_alloc_skb(length: len); |
176 | if (!skb) { |
177 | dev->net->stats.rx_dropped++; |
178 | return -ENOMEM; |
179 | } |
180 | |
181 | skb_put_data(skb, data: buf, len); |
182 | skb->dev = dev->net; |
183 | skb->protocol = eth_type_trans(skb, dev: dev->net); |
184 | |
185 | dev->net->stats.rx_packets++; |
186 | dev->net->stats.rx_bytes += len; |
187 | netif_rx(skb); |
188 | |
189 | return 0; |
190 | } |
191 | |
192 | static int ipheth_rcvbulk_callback_legacy(struct urb *urb) |
193 | { |
194 | struct ipheth_device *dev; |
195 | char *buf; |
196 | int len; |
197 | |
198 | dev = urb->context; |
199 | |
200 | if (urb->actual_length <= IPHETH_IP_ALIGN) { |
201 | dev->net->stats.rx_length_errors++; |
202 | return -EINVAL; |
203 | } |
204 | len = urb->actual_length - IPHETH_IP_ALIGN; |
205 | buf = urb->transfer_buffer + IPHETH_IP_ALIGN; |
206 | |
207 | return ipheth_consume_skb(buf, len, dev); |
208 | } |
209 | |
210 | static int ipheth_rcvbulk_callback_ncm(struct urb *urb) |
211 | { |
212 | struct usb_cdc_ncm_nth16 *ncmh; |
213 | struct usb_cdc_ncm_ndp16 *ncm0; |
214 | struct usb_cdc_ncm_dpe16 *dpe; |
215 | struct ipheth_device *dev; |
216 | int retval = -EINVAL; |
217 | char *buf; |
218 | int len; |
219 | |
220 | dev = urb->context; |
221 | |
222 | if (urb->actual_length < IPHETH_NCM_HEADER_SIZE) { |
223 | dev->net->stats.rx_length_errors++; |
224 | return retval; |
225 | } |
226 | |
227 | ncmh = urb->transfer_buffer; |
228 | if (ncmh->dwSignature != cpu_to_le32(USB_CDC_NCM_NTH16_SIGN) || |
229 | le16_to_cpu(ncmh->wNdpIndex) >= urb->actual_length) { |
230 | dev->net->stats.rx_errors++; |
231 | return retval; |
232 | } |
233 | |
234 | ncm0 = urb->transfer_buffer + le16_to_cpu(ncmh->wNdpIndex); |
235 | if (ncm0->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN) || |
236 | le16_to_cpu(ncmh->wHeaderLength) + le16_to_cpu(ncm0->wLength) >= |
237 | urb->actual_length) { |
238 | dev->net->stats.rx_errors++; |
239 | return retval; |
240 | } |
241 | |
242 | dpe = ncm0->dpe16; |
243 | while (le16_to_cpu(dpe->wDatagramIndex) != 0 && |
244 | le16_to_cpu(dpe->wDatagramLength) != 0) { |
245 | if (le16_to_cpu(dpe->wDatagramIndex) >= urb->actual_length || |
246 | le16_to_cpu(dpe->wDatagramIndex) + |
247 | le16_to_cpu(dpe->wDatagramLength) > urb->actual_length) { |
248 | dev->net->stats.rx_length_errors++; |
249 | return retval; |
250 | } |
251 | |
252 | buf = urb->transfer_buffer + le16_to_cpu(dpe->wDatagramIndex); |
253 | len = le16_to_cpu(dpe->wDatagramLength); |
254 | |
255 | retval = ipheth_consume_skb(buf, len, dev); |
256 | if (retval != 0) |
257 | return retval; |
258 | |
259 | dpe++; |
260 | } |
261 | |
262 | return 0; |
263 | } |
264 | |
265 | static void ipheth_rcvbulk_callback(struct urb *urb) |
266 | { |
267 | struct ipheth_device *dev; |
268 | int retval, status; |
269 | |
270 | dev = urb->context; |
271 | if (dev == NULL) |
272 | return; |
273 | |
274 | status = urb->status; |
275 | switch (status) { |
276 | case -ENOENT: |
277 | case -ECONNRESET: |
278 | case -ESHUTDOWN: |
279 | case -EPROTO: |
280 | return; |
281 | case 0: |
282 | break; |
283 | default: |
284 | dev_err(&dev->intf->dev, "%s: urb status: %d\n" , |
285 | __func__, status); |
286 | return; |
287 | } |
288 | |
289 | if (urb->actual_length <= IPHETH_IP_ALIGN) { |
290 | dev->net->stats.rx_length_errors++; |
291 | return; |
292 | } |
293 | |
294 | /* RX URBs starting with 0x00 0x01 do not encapsulate Ethernet frames, |
295 | * but rather are control frames. Their purpose is not documented, and |
296 | * they don't affect driver functionality, okay to drop them. |
297 | * There is usually just one 4-byte control frame as the very first |
298 | * URB received from the bulk IN endpoint. |
299 | */ |
300 | if (unlikely |
301 | (((char *)urb->transfer_buffer)[0] == 0 && |
302 | ((char *)urb->transfer_buffer)[1] == 1)) |
303 | goto rx_submit; |
304 | |
305 | retval = dev->rcvbulk_callback(urb); |
306 | if (retval != 0) { |
307 | dev_err(&dev->intf->dev, "%s: callback retval: %d\n" , |
308 | __func__, retval); |
309 | return; |
310 | } |
311 | |
312 | rx_submit: |
313 | dev->confirmed_pairing = true; |
314 | ipheth_rx_submit(dev, GFP_ATOMIC); |
315 | } |
316 | |
317 | static void ipheth_sndbulk_callback(struct urb *urb) |
318 | { |
319 | struct ipheth_device *dev; |
320 | int status = urb->status; |
321 | |
322 | dev = urb->context; |
323 | if (dev == NULL) |
324 | return; |
325 | |
326 | if (status != 0 && |
327 | status != -ENOENT && |
328 | status != -ECONNRESET && |
329 | status != -ESHUTDOWN) |
330 | dev_err(&dev->intf->dev, "%s: urb status: %d\n" , |
331 | __func__, status); |
332 | |
333 | if (status == 0) |
334 | netif_wake_queue(dev: dev->net); |
335 | else |
336 | // on URB error, trigger immediate poll |
337 | schedule_delayed_work(dwork: &dev->carrier_work, delay: 0); |
338 | } |
339 | |
340 | static int ipheth_carrier_set(struct ipheth_device *dev) |
341 | { |
342 | struct usb_device *udev; |
343 | int retval; |
344 | |
345 | if (!dev->confirmed_pairing) |
346 | return 0; |
347 | |
348 | udev = dev->udev; |
349 | retval = usb_control_msg(dev: udev, |
350 | usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP), |
351 | IPHETH_CMD_CARRIER_CHECK, /* request */ |
352 | requesttype: 0xc0, /* request type */ |
353 | value: 0x00, /* value */ |
354 | index: 0x02, /* index */ |
355 | data: dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE, |
356 | IPHETH_CTRL_TIMEOUT); |
357 | if (retval < 0) { |
358 | dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n" , |
359 | __func__, retval); |
360 | return retval; |
361 | } |
362 | |
363 | if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) { |
364 | netif_carrier_on(dev: dev->net); |
365 | if (dev->tx_urb->status != -EINPROGRESS) |
366 | netif_wake_queue(dev: dev->net); |
367 | } else { |
368 | netif_carrier_off(dev: dev->net); |
369 | netif_stop_queue(dev: dev->net); |
370 | } |
371 | return 0; |
372 | } |
373 | |
374 | static void ipheth_carrier_check_work(struct work_struct *work) |
375 | { |
376 | struct ipheth_device *dev = container_of(work, struct ipheth_device, |
377 | carrier_work.work); |
378 | |
379 | ipheth_carrier_set(dev); |
380 | schedule_delayed_work(dwork: &dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); |
381 | } |
382 | |
383 | static int ipheth_get_macaddr(struct ipheth_device *dev) |
384 | { |
385 | struct usb_device *udev = dev->udev; |
386 | struct net_device *net = dev->net; |
387 | int retval; |
388 | |
389 | retval = usb_control_msg(dev: udev, |
390 | usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP), |
391 | IPHETH_CMD_GET_MACADDR, /* request */ |
392 | requesttype: 0xc0, /* request type */ |
393 | value: 0x00, /* value */ |
394 | index: 0x02, /* index */ |
395 | data: dev->ctrl_buf, |
396 | IPHETH_CTRL_BUF_SIZE, |
397 | IPHETH_CTRL_TIMEOUT); |
398 | if (retval < 0) { |
399 | dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n" , |
400 | __func__, retval); |
401 | } else if (retval < ETH_ALEN) { |
402 | dev_err(&dev->intf->dev, |
403 | "%s: usb_control_msg: short packet: %d bytes\n" , |
404 | __func__, retval); |
405 | retval = -EINVAL; |
406 | } else { |
407 | eth_hw_addr_set(dev: net, addr: dev->ctrl_buf); |
408 | retval = 0; |
409 | } |
410 | |
411 | return retval; |
412 | } |
413 | |
414 | static int ipheth_enable_ncm(struct ipheth_device *dev) |
415 | { |
416 | struct usb_device *udev = dev->udev; |
417 | int retval; |
418 | |
419 | retval = usb_control_msg(dev: udev, |
420 | usb_sndctrlpipe(udev, IPHETH_CTRL_ENDP), |
421 | IPHETH_CMD_ENABLE_NCM, /* request */ |
422 | requesttype: 0x41, /* request type */ |
423 | value: 0x00, /* value */ |
424 | index: 0x02, /* index */ |
425 | NULL, |
426 | size: 0, |
427 | IPHETH_CTRL_TIMEOUT); |
428 | |
429 | dev_info(&dev->intf->dev, "%s: usb_control_msg: %d\n" , |
430 | __func__, retval); |
431 | |
432 | return retval; |
433 | } |
434 | |
435 | static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags) |
436 | { |
437 | struct usb_device *udev = dev->udev; |
438 | int retval; |
439 | |
440 | usb_fill_bulk_urb(urb: dev->rx_urb, dev: udev, |
441 | usb_rcvbulkpipe(udev, dev->bulk_in), |
442 | transfer_buffer: dev->rx_buf, buffer_length: dev->rx_buf_len, |
443 | complete_fn: ipheth_rcvbulk_callback, |
444 | context: dev); |
445 | dev->rx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
446 | |
447 | retval = usb_submit_urb(urb: dev->rx_urb, mem_flags); |
448 | if (retval) |
449 | dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n" , |
450 | __func__, retval); |
451 | return retval; |
452 | } |
453 | |
454 | static int ipheth_open(struct net_device *net) |
455 | { |
456 | struct ipheth_device *dev = netdev_priv(dev: net); |
457 | struct usb_device *udev = dev->udev; |
458 | int retval = 0; |
459 | |
460 | usb_set_interface(dev: udev, IPHETH_INTFNUM, IPHETH_ALT_INTFNUM); |
461 | |
462 | retval = ipheth_carrier_set(dev); |
463 | if (retval) |
464 | return retval; |
465 | |
466 | retval = ipheth_rx_submit(dev, GFP_KERNEL); |
467 | if (retval) |
468 | return retval; |
469 | |
470 | schedule_delayed_work(dwork: &dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT); |
471 | return retval; |
472 | } |
473 | |
474 | static int ipheth_close(struct net_device *net) |
475 | { |
476 | struct ipheth_device *dev = netdev_priv(dev: net); |
477 | |
478 | cancel_delayed_work_sync(dwork: &dev->carrier_work); |
479 | netif_stop_queue(dev: net); |
480 | return 0; |
481 | } |
482 | |
483 | static netdev_tx_t ipheth_tx(struct sk_buff *skb, struct net_device *net) |
484 | { |
485 | struct ipheth_device *dev = netdev_priv(dev: net); |
486 | struct usb_device *udev = dev->udev; |
487 | int retval; |
488 | |
489 | /* Paranoid */ |
490 | if (skb->len > IPHETH_TX_BUF_SIZE) { |
491 | WARN(1, "%s: skb too large: %d bytes\n" , __func__, skb->len); |
492 | dev->net->stats.tx_dropped++; |
493 | dev_kfree_skb_any(skb); |
494 | return NETDEV_TX_OK; |
495 | } |
496 | |
497 | memcpy(dev->tx_buf, skb->data, skb->len); |
498 | |
499 | usb_fill_bulk_urb(urb: dev->tx_urb, dev: udev, |
500 | usb_sndbulkpipe(udev, dev->bulk_out), |
501 | transfer_buffer: dev->tx_buf, buffer_length: skb->len, |
502 | complete_fn: ipheth_sndbulk_callback, |
503 | context: dev); |
504 | dev->tx_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
505 | |
506 | netif_stop_queue(dev: net); |
507 | retval = usb_submit_urb(urb: dev->tx_urb, GFP_ATOMIC); |
508 | if (retval) { |
509 | dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n" , |
510 | __func__, retval); |
511 | dev->net->stats.tx_errors++; |
512 | dev_kfree_skb_any(skb); |
513 | netif_wake_queue(dev: net); |
514 | } else { |
515 | dev->net->stats.tx_packets++; |
516 | dev->net->stats.tx_bytes += skb->len; |
517 | dev_consume_skb_any(skb); |
518 | } |
519 | |
520 | return NETDEV_TX_OK; |
521 | } |
522 | |
523 | static void ipheth_tx_timeout(struct net_device *net, unsigned int txqueue) |
524 | { |
525 | struct ipheth_device *dev = netdev_priv(dev: net); |
526 | |
527 | dev_err(&dev->intf->dev, "%s: TX timeout\n" , __func__); |
528 | dev->net->stats.tx_errors++; |
529 | usb_unlink_urb(urb: dev->tx_urb); |
530 | } |
531 | |
532 | static u32 ipheth_ethtool_op_get_link(struct net_device *net) |
533 | { |
534 | struct ipheth_device *dev = netdev_priv(dev: net); |
535 | return netif_carrier_ok(dev: dev->net); |
536 | } |
537 | |
538 | static const struct ethtool_ops ops = { |
539 | .get_link = ipheth_ethtool_op_get_link |
540 | }; |
541 | |
542 | static const struct net_device_ops ipheth_netdev_ops = { |
543 | .ndo_open = ipheth_open, |
544 | .ndo_stop = ipheth_close, |
545 | .ndo_start_xmit = ipheth_tx, |
546 | .ndo_tx_timeout = ipheth_tx_timeout, |
547 | }; |
548 | |
549 | static int ipheth_probe(struct usb_interface *intf, |
550 | const struct usb_device_id *id) |
551 | { |
552 | struct usb_device *udev = interface_to_usbdev(intf); |
553 | struct usb_host_interface *hintf; |
554 | struct usb_endpoint_descriptor *endp; |
555 | struct ipheth_device *dev; |
556 | struct net_device *netdev; |
557 | int i; |
558 | int retval; |
559 | |
560 | netdev = alloc_etherdev(sizeof(struct ipheth_device)); |
561 | if (!netdev) |
562 | return -ENOMEM; |
563 | |
564 | netdev->netdev_ops = &ipheth_netdev_ops; |
565 | netdev->watchdog_timeo = IPHETH_TX_TIMEOUT; |
566 | strscpy(p: netdev->name, q: "eth%d" , size: sizeof(netdev->name)); |
567 | |
568 | dev = netdev_priv(dev: netdev); |
569 | dev->udev = udev; |
570 | dev->net = netdev; |
571 | dev->intf = intf; |
572 | dev->confirmed_pairing = false; |
573 | dev->rx_buf_len = IPHETH_RX_BUF_SIZE_LEGACY; |
574 | dev->rcvbulk_callback = ipheth_rcvbulk_callback_legacy; |
575 | /* Set up endpoints */ |
576 | hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM); |
577 | if (hintf == NULL) { |
578 | retval = -ENODEV; |
579 | dev_err(&intf->dev, "Unable to find alternate settings interface\n" ); |
580 | goto err_endpoints; |
581 | } |
582 | |
583 | for (i = 0; i < hintf->desc.bNumEndpoints; i++) { |
584 | endp = &hintf->endpoint[i].desc; |
585 | if (usb_endpoint_is_bulk_in(epd: endp)) |
586 | dev->bulk_in = endp->bEndpointAddress; |
587 | else if (usb_endpoint_is_bulk_out(epd: endp)) |
588 | dev->bulk_out = endp->bEndpointAddress; |
589 | } |
590 | if (!(dev->bulk_in && dev->bulk_out)) { |
591 | retval = -ENODEV; |
592 | dev_err(&intf->dev, "Unable to find endpoints\n" ); |
593 | goto err_endpoints; |
594 | } |
595 | |
596 | dev->ctrl_buf = kmalloc(IPHETH_CTRL_BUF_SIZE, GFP_KERNEL); |
597 | if (dev->ctrl_buf == NULL) { |
598 | retval = -ENOMEM; |
599 | goto err_alloc_ctrl_buf; |
600 | } |
601 | |
602 | retval = ipheth_get_macaddr(dev); |
603 | if (retval) |
604 | goto err_get_macaddr; |
605 | |
606 | retval = ipheth_enable_ncm(dev); |
607 | if (!retval) { |
608 | dev->rx_buf_len = IPHETH_RX_BUF_SIZE_NCM; |
609 | dev->rcvbulk_callback = ipheth_rcvbulk_callback_ncm; |
610 | } |
611 | |
612 | INIT_DELAYED_WORK(&dev->carrier_work, ipheth_carrier_check_work); |
613 | |
614 | retval = ipheth_alloc_urbs(iphone: dev); |
615 | if (retval) { |
616 | dev_err(&intf->dev, "error allocating urbs: %d\n" , retval); |
617 | goto err_alloc_urbs; |
618 | } |
619 | |
620 | usb_set_intfdata(intf, data: dev); |
621 | |
622 | SET_NETDEV_DEV(netdev, &intf->dev); |
623 | netdev->ethtool_ops = &ops; |
624 | |
625 | retval = register_netdev(dev: netdev); |
626 | if (retval) { |
627 | dev_err(&intf->dev, "error registering netdev: %d\n" , retval); |
628 | retval = -EIO; |
629 | goto err_register_netdev; |
630 | } |
631 | // carrier down and transmit queues stopped until packet from device |
632 | netif_carrier_off(dev: netdev); |
633 | netif_tx_stop_all_queues(dev: netdev); |
634 | dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n" ); |
635 | return 0; |
636 | |
637 | err_register_netdev: |
638 | ipheth_free_urbs(iphone: dev); |
639 | err_alloc_urbs: |
640 | err_get_macaddr: |
641 | kfree(objp: dev->ctrl_buf); |
642 | err_alloc_ctrl_buf: |
643 | err_endpoints: |
644 | free_netdev(dev: netdev); |
645 | return retval; |
646 | } |
647 | |
648 | static void ipheth_disconnect(struct usb_interface *intf) |
649 | { |
650 | struct ipheth_device *dev; |
651 | |
652 | dev = usb_get_intfdata(intf); |
653 | if (dev != NULL) { |
654 | unregister_netdev(dev: dev->net); |
655 | ipheth_kill_urbs(dev); |
656 | ipheth_free_urbs(iphone: dev); |
657 | kfree(objp: dev->ctrl_buf); |
658 | free_netdev(dev: dev->net); |
659 | } |
660 | usb_set_intfdata(intf, NULL); |
661 | dev_info(&intf->dev, "Apple iPhone USB Ethernet now disconnected\n" ); |
662 | } |
663 | |
664 | static struct usb_driver ipheth_driver = { |
665 | .name = "ipheth" , |
666 | .probe = ipheth_probe, |
667 | .disconnect = ipheth_disconnect, |
668 | .id_table = ipheth_table, |
669 | .disable_hub_initiated_lpm = 1, |
670 | }; |
671 | |
672 | module_usb_driver(ipheth_driver); |
673 | |
674 | MODULE_AUTHOR("Diego Giagio <diego@giagio.com>" ); |
675 | MODULE_DESCRIPTION("Apple iPhone USB Ethernet driver" ); |
676 | MODULE_LICENSE("Dual BSD/GPL" ); |
677 | |