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@
This commit is contained in:
br 2015-01-17 12:31:26 +00:00
parent 240f3ae6d2
commit c13d70380d
2 changed files with 60 additions and 6 deletions

View File

@ -898,7 +898,13 @@ 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 */
/*
* 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 */
@ -1065,6 +1071,10 @@ cdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error)
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);
/*
* 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);
#endif
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 */

View File

@ -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)