diff options
author | br <br@FreeBSD.org> | 2015-01-17 12:31:26 +0000 |
---|---|---|
committer | br <br@FreeBSD.org> | 2015-01-17 12:31:26 +0000 |
commit | c13d70380d4abc45ee62004df19a9837a468fb7a (patch) | |
tree | b0dd334d4b5727e8967d11b36671f6f8aa39e601 | |
parent | 240f3ae6d2481bc5a902c2527ff1205ba2af9552 (diff) | |
download | FreeBSD-src-c13d70380d4abc45ee62004df19a9837a468fb7a.zip FreeBSD-src-c13d70380d4abc45ee62004df19a9837a468fb7a.tar.gz |
o Notify USB host about connection when operating in device mode.
Required when communicating to Mac OS X USB host stack.
o Also don't set stall bit to TX pipe in device mode as seems Mac OS X
don't clears it as it should.
Discussed with: hselasky@
-rw-r--r-- | sys/dev/usb/net/if_cdce.c | 62 | ||||
-rw-r--r-- | sys/dev/usb/net/if_cdcereg.h | 4 |
2 files changed, 60 insertions, 6 deletions
diff --git a/sys/dev/usb/net/if_cdce.c b/sys/dev/usb/net/if_cdce.c index e42305a..76134ba 100644 --- a/sys/dev/usb/net/if_cdce.c +++ b/sys/dev/usb/net/if_cdce.c @@ -898,8 +898,14 @@ cdce_init(struct usb_ether *ue) usbd_transfer_start(sc->sc_xfer[CDCE_INTR_RX]); usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]); - /* stall data write direction, which depends on USB mode */ - usbd_xfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]); + /* + * Stall data write direction, which depends on USB mode. + * + * Some USB host stacks (e.g. Mac OS X) don't clears stall + * bit as it should, so set it in our host mode only. + */ + if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) + usbd_xfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]); /* start data transfers */ cdce_start(ue); @@ -1065,6 +1071,10 @@ tr_setup: static void cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) { + struct cdce_softc *sc = usbd_xfer_softc(xfer); + struct usb_cdc_notification req; + struct usb_page_cache *pc; + uint32_t speed; int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); @@ -1077,10 +1087,50 @@ cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: -#if 0 - usbd_xfer_set_frame_len(xfer, 0, XXX); - usbd_transfer_submit(xfer); -#endif + /* + * Inform host about connection. Required according to USB CDC + * specification and communicating to Mac OS X USB host stack. + * Some of the values seems ignored by Mac OS X though. + */ + if (sc->sc_notify_state == CDCE_NOTIFY_NETWORK_CONNECTION) { + req.bmRequestType = UCDC_NOTIFICATION; + req.bNotification = UCDC_N_NETWORK_CONNECTION; + req.wIndex[0] = sc->sc_ifaces_index[1]; + req.wIndex[1] = 0; + USETW(req.wValue, 1); /* Connected */ + USETW(req.wLength, 0); + + pc = usbd_xfer_get_frame(xfer, 0); + usbd_copy_in(pc, 0, &req, sizeof(req)); + 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; + req.bNotification = UCDC_N_CONNECTION_SPEED_CHANGE; + req.wIndex[0] = sc->sc_ifaces_index[1]; + req.wIndex[1] = 0; + USETW(req.wValue, 0); + USETW(req.wLength, 8); + + /* Peak theoretical bulk trasfer rate in bits/s */ + if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_HIGH) + speed = (13 * 512 * 8 * 1000 * 8); + else + speed = (19 * 64 * 1 * 1000 * 8); + + USETDW(req.data + 0, speed); /* Upstream bit rate */ + USETDW(req.data + 4, speed); /* Downstream bit rate */ + + pc = usbd_xfer_get_frame(xfer, 0); + usbd_copy_in(pc, 0, &req, sizeof(req)); + 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 */ diff --git a/sys/dev/usb/net/if_cdcereg.h b/sys/dev/usb/net/if_cdcereg.h index c470b36..1bc2d60 100644 --- a/sys/dev/usb/net/if_cdcereg.h +++ b/sys/dev/usb/net/if_cdcereg.h @@ -93,6 +93,10 @@ struct cdce_softc { uint8_t sc_eaddr_str_index; uint8_t sc_ifaces_index[2]; + uint8_t sc_notify_state; +#define CDCE_NOTIFY_NETWORK_CONNECTION 0 +#define CDCE_NOTIFY_SPEED_CHANGE 1 +#define CDCE_NOTIFY_DONE 2 }; #define CDCE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) |