|
@@ -149,6 +149,7 @@ struct ipheth_device {
|
|
|
u8 bulk_in;
|
|
|
u8 bulk_out;
|
|
|
struct delayed_work carrier_work;
|
|
|
+ bool confirmed_pairing;
|
|
|
};
|
|
|
|
|
|
static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags);
|
|
@@ -259,7 +260,7 @@ static void ipheth_rcvbulk_callback(struct urb *urb)
|
|
|
|
|
|
dev->net->stats.rx_packets++;
|
|
|
dev->net->stats.rx_bytes += len;
|
|
|
-
|
|
|
+ dev->confirmed_pairing = true;
|
|
|
netif_rx(skb);
|
|
|
ipheth_rx_submit(dev, GFP_ATOMIC);
|
|
|
}
|
|
@@ -281,14 +282,21 @@ static void ipheth_sndbulk_callback(struct urb *urb)
|
|
|
__func__, status);
|
|
|
|
|
|
dev_kfree_skb_irq(dev->tx_skb);
|
|
|
- netif_wake_queue(dev->net);
|
|
|
+ if (status == 0)
|
|
|
+ netif_wake_queue(dev->net);
|
|
|
+ else
|
|
|
+ // on URB error, trigger immediate poll
|
|
|
+ schedule_delayed_work(&dev->carrier_work, 0);
|
|
|
}
|
|
|
|
|
|
static int ipheth_carrier_set(struct ipheth_device *dev)
|
|
|
{
|
|
|
struct usb_device *udev = dev->udev;
|
|
|
int retval;
|
|
|
-
|
|
|
+ if (!dev)
|
|
|
+ return 0;
|
|
|
+ if (!dev->confirmed_pairing)
|
|
|
+ return 0;
|
|
|
retval = usb_control_msg(udev,
|
|
|
usb_rcvctrlpipe(udev, IPHETH_CTRL_ENDP),
|
|
|
IPHETH_CMD_CARRIER_CHECK, /* request */
|
|
@@ -303,11 +311,14 @@ static int ipheth_carrier_set(struct ipheth_device *dev)
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
- if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON)
|
|
|
+ if (dev->ctrl_buf[0] == IPHETH_CARRIER_ON) {
|
|
|
netif_carrier_on(dev->net);
|
|
|
- else
|
|
|
+ if (dev->tx_urb->status != -EINPROGRESS)
|
|
|
+ netif_wake_queue(dev->net);
|
|
|
+ } else {
|
|
|
netif_carrier_off(dev->net);
|
|
|
-
|
|
|
+ netif_stop_queue(dev->net);
|
|
|
+ }
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -387,7 +398,6 @@ static int ipheth_open(struct net_device *net)
|
|
|
return retval;
|
|
|
|
|
|
schedule_delayed_work(&dev->carrier_work, IPHETH_CARRIER_CHECK_TIMEOUT);
|
|
|
- netif_start_queue(net);
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
@@ -491,7 +501,7 @@ static int ipheth_probe(struct usb_interface *intf,
|
|
|
dev->udev = udev;
|
|
|
dev->net = netdev;
|
|
|
dev->intf = intf;
|
|
|
-
|
|
|
+ dev->confirmed_pairing = false;
|
|
|
/* Set up endpoints */
|
|
|
hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
|
|
|
if (hintf == NULL) {
|
|
@@ -542,7 +552,9 @@ static int ipheth_probe(struct usb_interface *intf,
|
|
|
retval = -EIO;
|
|
|
goto err_register_netdev;
|
|
|
}
|
|
|
-
|
|
|
+ // carrier down and transmit queues stopped until packet from device
|
|
|
+ netif_carrier_off(netdev);
|
|
|
+ netif_tx_stop_all_queues(netdev);
|
|
|
dev_info(&intf->dev, "Apple iPhone USB Ethernet device attached\n");
|
|
|
return 0;
|
|
|
|