summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorbr <br@FreeBSD.org>2015-01-20 15:45:09 +0000
committerbr <br@FreeBSD.org>2015-01-20 15:45:09 +0000
commit9896a88f220b781873672a420aae843c3150710b (patch)
tree60067d6ace663d2748001aca651ced19ba5b2524 /sys/dev/usb
parent24b6750419f6979b7cbb18a485d70d553fcb9fcd (diff)
downloadFreeBSD-src-9896a88f220b781873672a420aae843c3150710b.zip
FreeBSD-src-9896a88f220b781873672a420aae843c3150710b.tar.gz
o Do notify USB host each time we receive 'set packet filter' request.
This makes Mac OS X happy when it returns back from suspending. o Switch notify state after data is transferred, but not before. o Consider there is also Super Speed mode. o Do not set stall bit on any pipes in device mode as Mac OS X seems don't support it. In collaboration with: hselasky@
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/net/if_cdce.c93
1 files changed, 69 insertions, 24 deletions
diff --git a/sys/dev/usb/net/if_cdce.c b/sys/dev/usb/net/if_cdce.c
index 76134ba..6824fbc 100644
--- a/sys/dev/usb/net/if_cdce.c
+++ b/sys/dev/usb/net/if_cdce.c
@@ -857,9 +857,12 @@ tr_setup:
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
if (error != USB_ERR_CANCELLED) {
- /* try to clear stall first */
- usbd_xfer_set_stall(xfer);
- goto tr_setup;
+ if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) {
+ /* try to clear stall first */
+ usbd_xfer_set_stall(xfer);
+ } else {
+ goto tr_setup;
+ }
}
break;
}
@@ -1024,10 +1027,12 @@ cdce_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
if (error != USB_ERR_CANCELLED) {
tr_stall:
- /* try to clear stall first */
- usbd_xfer_set_stall(xfer);
- usbd_xfer_set_frames(xfer, 0);
- usbd_transfer_submit(xfer);
+ if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) {
+ /* try to clear stall first */
+ usbd_xfer_set_stall(xfer);
+ usbd_xfer_set_frames(xfer, 0);
+ usbd_transfer_submit(xfer);
+ }
break;
}
@@ -1040,6 +1045,7 @@ tr_stall:
static void
cdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
{
+ struct cdce_softc *sc = usbd_xfer_softc(xfer);
int actlen;
usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
@@ -1061,8 +1067,10 @@ tr_setup:
default: /* Error */
if (error != USB_ERR_CANCELLED) {
/* start clear stall */
- usbd_xfer_set_stall(xfer);
- goto tr_setup;
+ if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST)
+ usbd_xfer_set_stall(xfer);
+ else
+ goto tr_setup;
}
break;
}
@@ -1084,6 +1092,17 @@ cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error)
DPRINTF("Transferred %d bytes\n", actlen);
+ switch (sc->sc_notify_state) {
+ case (CDCE_NOTIFY_NETWORK_CONNECTION):
+ sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE;
+ break;
+ case (CDCE_NOTIFY_SPEED_CHANGE):
+ sc->sc_notify_state = CDCE_NOTIFY_DONE;
+ break;
+ default:
+ break;
+ }
+
/* FALLTHROUGH */
case USB_ST_SETUP:
tr_setup:
@@ -1105,7 +1124,6 @@ tr_setup:
usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
usbd_xfer_set_frames(xfer, 1);
usbd_transfer_submit(xfer);
- sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE;
} else if (sc->sc_notify_state == CDCE_NOTIFY_SPEED_CHANGE) {
req.bmRequestType = UCDC_NOTIFICATION;
@@ -1116,7 +1134,7 @@ tr_setup:
USETW(req.wLength, 8);
/* Peak theoretical bulk trasfer rate in bits/s */
- if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_HIGH)
+ if (usbd_get_speed(sc->sc_ue.ue_udev) != USB_SPEED_FULL)
speed = (13 * 512 * 8 * 1000 * 8);
else
speed = (19 * 64 * 1 * 1000 * 8);
@@ -1129,15 +1147,17 @@ tr_setup:
usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
usbd_xfer_set_frames(xfer, 1);
usbd_transfer_submit(xfer);
- sc->sc_notify_state = CDCE_NOTIFY_DONE;
}
break;
default: /* Error */
if (error != USB_ERR_CANCELLED) {
- /* start clear stall */
- usbd_xfer_set_stall(xfer);
- goto tr_setup;
+ if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) {
+ /* start clear stall */
+ usbd_xfer_set_stall(xfer);
+ } else {
+ goto tr_setup;
+ }
}
break;
}
@@ -1145,9 +1165,30 @@ tr_setup:
static int
cdce_handle_request(device_t dev,
- const void *req, void **pptr, uint16_t *plen,
+ const void *preq, void **pptr, uint16_t *plen,
uint16_t offset, uint8_t *pstate)
{
+ struct cdce_softc *sc = device_get_softc(dev);
+ const struct usb_device_request *req = preq;
+ uint8_t is_complete = *pstate;
+
+ /*
+ * When Mac OS X resumes after suspending it expects
+ * to be notified again after this request.
+ */
+ if (req->bmRequestType == UT_WRITE_CLASS_INTERFACE && \
+ req->bRequest == UCDC_NCM_SET_ETHERNET_PACKET_FILTER) {
+
+ if (is_complete == 1) {
+ mtx_lock(&sc->sc_mtx);
+ sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE;
+ usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]);
+ mtx_unlock(&sc->sc_mtx);
+ }
+
+ return (0);
+ }
+
return (ENXIO); /* use builtin handler */
}
@@ -1363,10 +1404,12 @@ cdce_ncm_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
if (error != USB_ERR_CANCELLED) {
- /* try to clear stall first */
- usbd_xfer_set_stall(xfer);
- usbd_xfer_set_frames(xfer, 0);
- usbd_transfer_submit(xfer);
+ if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) {
+ /* try to clear stall first */
+ usbd_xfer_set_stall(xfer);
+ usbd_xfer_set_frames(xfer, 0);
+ usbd_transfer_submit(xfer);
+ }
}
break;
}
@@ -1524,10 +1567,12 @@ tr_setup:
if (error != USB_ERR_CANCELLED) {
tr_stall:
- /* try to clear stall first */
- usbd_xfer_set_stall(xfer);
- usbd_xfer_set_frames(xfer, 0);
- usbd_transfer_submit(xfer);
+ if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) {
+ /* try to clear stall first */
+ usbd_xfer_set_stall(xfer);
+ usbd_xfer_set_frames(xfer, 0);
+ usbd_transfer_submit(xfer);
+ }
}
break;
}
OpenPOWER on IntegriCloud