static void uhid_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct uhid_softc *sc = usbd_xfer_softc(xfer); struct usb_device_request req; struct usb_page_cache *pc; uint32_t size = sc->sc_osize; uint32_t actlen; uint8_t id; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: case USB_ST_SETUP: /* try to extract the ID byte */ if (sc->sc_oid) { pc = usbd_xfer_get_frame(xfer, 0); if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc, 0, 1, &actlen, 0)) { if (actlen != 1) { goto tr_error; } usbd_copy_out(pc, 0, &id, 1); } else { return; } if (size) { size--; } } else { id = 0; } pc = usbd_xfer_get_frame(xfer, 1); if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc, 0, UHID_BSIZE, &actlen, 1)) { if (actlen != size) { goto tr_error; } uhid_fill_set_report (&req, sc->sc_iface_no, UHID_OUTPUT_REPORT, id, size); 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_frame_len(xfer, 1, size); usbd_xfer_set_frames(xfer, size ? 2 : 1); usbd_transfer_submit(xfer); } return; default: tr_error: /* bomb out */ usb_fifo_get_data_error(sc->sc_fifo.fp[USB_FIFO_TX]); return; } }
static void uhso_mux_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct uhso_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; struct usb_device_request req; struct uhso_tty *ht; int actlen, len; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); UHSO_DPRINTF(3, "status %d\n", USB_GET_STATE(xfer)); ht = usbd_xfer_get_priv(xfer); UHSO_DPRINTF(3, "ht=%p open=%d\n", ht, ht->ht_open); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: /* Got data, send to ucom */ pc = usbd_xfer_get_frame(xfer, 1); len = usbd_xfer_frame_len(xfer, 1); UHSO_DPRINTF(3, "got %d bytes on mux port %d\n", len, ht->ht_muxport); if (len <= 0) { usbd_transfer_start(sc->sc_xfer[UHSO_MUX_ENDPT_INTR]); break; } /* Deliver data if the TTY is open, discard otherwise */ if (ht->ht_open) ucom_put_data(&sc->sc_ucom[ht->ht_muxport], pc, 0, len); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: memset(&req, 0, sizeof(struct usb_device_request)); req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE; USETW(req.wValue, 0); USETW(req.wIndex, ht->ht_muxport); USETW(req.wLength, 1024); 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_frame_len(xfer, 1, 1024); usbd_xfer_set_frames(xfer, 2); usbd_transfer_submit(xfer); break; default: UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); if (error == USB_ERR_CANCELLED) break; usbd_xfer_set_stall(xfer); goto tr_setup; } }
static void uhso_mux_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct uhso_softc *sc = usbd_xfer_softc(xfer); struct uhso_tty *ht; struct usb_page_cache *pc; struct usb_device_request req; int actlen; struct usb_page_search res; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); ht = usbd_xfer_get_priv(xfer); UHSO_DPRINTF(3, "status=%d, using mux port %d\n", USB_GET_STATE(xfer), ht->ht_muxport); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: UHSO_DPRINTF(3, "wrote %zd data bytes to muxport %d\n", actlen - sizeof(struct usb_device_request) , ht->ht_muxport); /* FALLTHROUGH */ case USB_ST_SETUP: pc = usbd_xfer_get_frame(xfer, 1); if (ucom_get_data(&sc->sc_ucom[ht->ht_muxport], pc, 0, 32, &actlen)) { usbd_get_page(pc, 0, &res); memset(&req, 0, sizeof(struct usb_device_request)); req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND; USETW(req.wValue, 0); USETW(req.wIndex, ht->ht_muxport); USETW(req.wLength, actlen); 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_frame_len(xfer, 1, actlen); usbd_xfer_set_frames(xfer, 2); UHSO_DPRINTF(3, "Prepared %d bytes for transmit " "on muxport %d\n", actlen, ht->ht_muxport); usbd_transfer_submit(xfer); } break; default: UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); if (error == USB_ERR_CANCELLED) break; break; } }
static void cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) { int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTF("Transferred %d bytes\n", actlen); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: #if 0 usbd_xfer_set_frame_len(xfer, 0, XXX); usbd_transfer_submit(xfer); #endif break; default: /* Error */ if (error != USB_ERR_CANCELLED) { /* start clear stall */ usbd_xfer_set_stall(xfer); goto tr_setup; } break; } }
static void uhso_bs_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct uhso_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); UHSO_DPRINTF(3, "status %d, actlen=%d\n", USB_GET_STATE(xfer), actlen); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: case USB_ST_SETUP: tr_setup: pc = usbd_xfer_get_frame(xfer, 0); if (ucom_get_data(&sc->sc_ucom[0], pc, 0, 8192, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } break; break; default: UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); if (error == USB_ERR_CANCELLED) break; usbd_xfer_set_stall(xfer); goto tr_setup; } }
static void ubt_isoc_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct ubt_softc *sc = usbd_xfer_softc(xfer); int n; int actlen, nframes; usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: for (n = 0; n < nframes; n ++) if (ubt_isoc_read_one_frame(xfer, n) < 0) break; /* FALLTHROUGH */ case USB_ST_SETUP: read_next: for (n = 0; n < nframes; n ++) usbd_xfer_set_frame_len(xfer, n, usbd_xfer_max_framelen(xfer)); usbd_transfer_submit(xfer); break; default: /* Error */ if (error != USB_ERR_CANCELLED) { UBT_STAT_IERROR(sc); goto read_next; } /* transfer cancelled */ break; } } /* ubt_isoc_read_callback */
static void cdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) { int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTF("Received %d bytes\n", actlen); /* TODO: decode some indications */ /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); break; default: /* Error */ if (error != USB_ERR_CANCELLED) { /* start clear stall */ usbd_xfer_set_stall(xfer); goto tr_setup; } break; } }
static void usie_uc_status_callback(struct usb_xfer *xfer, usb_error_t error) { struct usb_page_cache *pc; struct { struct usb_device_request req; uint16_t param; } st; uint32_t actlen; uint16_t param; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(4, "info received, actlen=%u\n", actlen); if (actlen < sizeof(st)) { DPRINTF("data too short actlen=%u\n", actlen); goto tr_setup; } pc = usbd_xfer_get_frame(xfer, 0); usbd_copy_out(pc, 0, &st, sizeof(st)); if (st.req.bmRequestType == 0xa1 && st.req.bRequest == 0x20) { struct ucom_softc *ucom = usbd_xfer_softc(xfer); struct usie_softc *sc = ucom->sc_parent; param = le16toh(st.param); DPRINTF("param=%x\n", param); sc->sc_msr = sc->sc_lsr = 0; sc->sc_msr |= (param & USIE_DCD) ? SER_DCD : 0; sc->sc_msr |= (param & USIE_DSR) ? SER_DSR : 0; sc->sc_msr |= (param & USIE_RI) ? SER_RI : 0; sc->sc_msr |= (param & USIE_CTS) ? 0 : SER_CTS; sc->sc_msr |= (param & USIE_RTS) ? SER_RTS : 0; sc->sc_msr |= (param & USIE_DTR) ? SER_DTR : 0; } /* fall though */ case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); break; default: /* Error */ DPRINTF("USB transfer error, %s\n", usbd_errstr(error)); if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); goto tr_setup; } break; } }
static void usie_uc_rx_callback(struct usb_xfer *xfer, usb_error_t error) { struct ucom_softc *ucom = usbd_xfer_softc(xfer); struct usie_softc *sc = ucom->sc_parent; struct usb_page_cache *pc; uint32_t actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: pc = usbd_xfer_get_frame(xfer, 0); /* handle CnS response */ if (ucom == sc->sc_ucom && actlen >= USIE_HIPCNS_MIN) { DPRINTF("transferred=%u\n", actlen); /* check if it is really CnS reply */ usbd_copy_out(pc, 0, sc->sc_resp_temp, 1); if (sc->sc_resp_temp[0] == USIE_HIP_FRM_CHR) { /* verify actlen */ if (actlen > USIE_BUFSIZE) actlen = USIE_BUFSIZE; /* get complete message */ usbd_copy_out(pc, 0, sc->sc_resp_temp, actlen); usie_hip_rsp(sc, sc->sc_resp_temp, actlen); /* need to fall though */ goto tr_setup; } /* else call ucom_put_data() */ } /* standard ucom transfer */ ucom_put_data(ucom, pc, 0, actlen); /* fall though */ case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); break; default: /* Error */ if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); goto tr_setup; } break; } }
/*------------------------------------------------------------------------* * usb_handle_request_callback * * This function is the USB callback for generic USB Device control * transfers. *------------------------------------------------------------------------*/ void usb_handle_request_callback(struct usb_xfer *xfer, usb_error_t error) { usb_error_t err; /* check the current transfer state */ switch (USB_GET_STATE(xfer)) { case USB_ST_SETUP: case USB_ST_TRANSFERRED: /* handle the request */ err = usb_handle_request(xfer); if (err) { if (err == USB_ERR_BAD_CONTEXT) { /* we need to re-setup the control transfer */ usb_needs_explore(xfer->xroot->bus, 0); break; } goto tr_restart; } usbd_transfer_submit(xfer); break; default: /* check if a control transfer is active */ if (xfer->flags_int.control_rem != 0xFFFF) { /* handle the request */ err = usb_handle_request(xfer); } if (xfer->error != USB_ERR_CANCELLED) { /* should not happen - try stalling */ goto tr_restart; } break; } return; tr_restart: /* * If a control transfer is active, stall it, and wait for the * next control transfer. */ usbd_xfer_set_frame_len(xfer, 0, sizeof(struct usb_device_request)); xfer->nframes = 1; xfer->flags.manual_status = 1; xfer->flags.force_short_xfer = 0; usbd_xfer_set_stall(xfer); /* cancel previous transfer, if any */ usbd_transfer_submit(xfer); }
static void usie_uc_tx_callback(struct usb_xfer *xfer, usb_error_t error) { struct ucom_softc *ucom = usbd_xfer_softc(xfer); struct usb_page_cache *pc; uint32_t actlen; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: case USB_ST_SETUP: tr_setup: pc = usbd_xfer_get_frame(xfer, 0); /* handle CnS request */ struct mbuf *m = usbd_xfer_get_priv(xfer); if (m != NULL) { usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len); usbd_xfer_set_priv(xfer, NULL); usbd_transfer_submit(xfer); m_freem(m); break; } /* standard ucom transfer */ if (ucom_get_data(ucom, pc, 0, USIE_BUFSIZE, &actlen)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } break; default: /* Error */ if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); goto tr_setup; } break; } }
static void ugen_isoc_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct usb_fifo *f = usbd_xfer_softc(xfer); usb_frlength_t actlen; usb_frlength_t offset; usb_frcount_t n; DPRINTFN(4, "actlen=%u, aframes=%u\n", xfer->actlen, xfer->aframes); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: case USB_ST_SETUP: tr_setup: offset = 0; for (n = 0; n != xfer->nframes; n++) { if (usb_fifo_get_data(f, xfer->frbuffers, offset, xfer->max_frame_size, &actlen, 1)) { usbd_xfer_set_frame_len(xfer, n, actlen); offset += actlen; } else { break; } } for (; n != xfer->nframes; n++) { /* fill in zero frames */ usbd_xfer_set_frame_len(xfer, n, 0); } usbd_transfer_submit(xfer); break; default: /* Error */ if (xfer->error == USB_ERR_CANCELLED) { break; } goto tr_setup; } }
static void ugen_default_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct usb_fifo *f = usbd_xfer_softc(xfer); struct usb_mbuf *m; DPRINTFN(4, "actlen=%u, aframes=%u\n", xfer->actlen, xfer->aframes); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: if (xfer->actlen == 0) { if (f->fifo_zlp != 4) { f->fifo_zlp++; } else { /* * Throttle a little bit we have multiple ZLPs * in a row! */ xfer->interval = 64; /* ms */ } } else { /* clear throttle */ xfer->interval = 0; f->fifo_zlp = 0; } usb_fifo_put_data(f, xfer->frbuffers, 0, xfer->actlen, 1); case USB_ST_SETUP: if (f->flag_stall) { usbd_transfer_start(f->xfer[1]); break; } USB_IF_POLL(&f->free_q, m); if (m) { usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); } break; default: /* Error */ if (xfer->error != USB_ERR_CANCELLED) { /* send a zero length packet to userland */ usb_fifo_put_data(f, xfer->frbuffers, 0, 0, 1); f->flag_stall = 1; f->fifo_zlp = 0; usbd_transfer_start(f->xfer[1]); } break; } }
static void uhid_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct uhid_softc *sc = usbd_xfer_softc(xfer); struct usb_device_request req; struct usb_page_cache *pc; pc = usbd_xfer_get_frame(xfer, 0); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: usb_fifo_put_data(sc->sc_fifo.fp[USB_FIFO_RX], pc, sizeof(req), sc->sc_isize, 1); return; case USB_ST_SETUP: if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) > 0) { uhid_fill_get_report (&req, sc->sc_iface_no, UHID_INPUT_REPORT, sc->sc_iid, sc->sc_isize); usbd_copy_in(pc, 0, &req, sizeof(req)); usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); usbd_xfer_set_frame_len(xfer, 1, sc->sc_isize); usbd_xfer_set_frames(xfer, sc->sc_isize ? 2 : 1); usbd_transfer_submit(xfer); } return; default: /* Error */ /* bomb out */ usb_fifo_put_data_error(sc->sc_fifo.fp[USB_FIFO_RX]); return; } }
/* * Interrupt callback for the multiplexed serial port. Indicates * which serial port has data waiting. */ static void uhso_mux_intr_callback(struct usb_xfer *xfer, usb_error_t error) { struct usb_page_cache *pc; struct usb_page_search res; struct uhso_softc *sc = usbd_xfer_softc(xfer); unsigned int i, mux; UHSO_DPRINTF(3, "status %d\n", USB_GET_STATE(xfer)); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: /* * The multiplexed port number can be found at the first byte. * It contains a bit mask, we transform this in to an integer. */ pc = usbd_xfer_get_frame(xfer, 0); usbd_get_page(pc, 0, &res); i = *((unsigned char *)res.buffer); mux = 0; while (i >>= 1) { mux++; } UHSO_DPRINTF(3, "mux port %d (%d)\n", mux, i); if (mux > UHSO_MPORT_TYPE_NOMAX) break; /* Issue a read for this serial port */ usbd_xfer_set_priv( sc->sc_tty[mux].ht_xfer[UHSO_CTRL_READ], &sc->sc_tty[mux]); usbd_transfer_start(sc->sc_tty[mux].ht_xfer[UHSO_CTRL_READ]); break; case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); break; default: UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); if (error == USB_ERR_CANCELLED) break; usbd_xfer_set_stall(xfer); goto tr_setup; } }
static void usie_if_status_callback(struct usb_xfer *xfer, usb_error_t error) { struct usie_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; struct usb_cdc_notification cdc; uint32_t actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(4, "info received, actlen=%d\n", actlen); /* usb_cdc_notification - .data[16] */ if (actlen < (sizeof(cdc) - 16)) { DPRINTF("data too short %d\n", actlen); goto tr_setup; } pc = usbd_xfer_get_frame(xfer, 0); usbd_copy_out(pc, 0, &cdc, (sizeof(cdc) - 16)); DPRINTFN(4, "bNotification=%x\n", cdc.bNotification); if (cdc.bNotification & UCDC_N_RESPONSE_AVAILABLE) { taskqueue_enqueue(taskqueue_thread, &sc->sc_if_status_task); } /* fall though */ case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); break; default: /* Error */ DPRINTF("USB transfer error, %s\n", usbd_errstr(error)); if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); goto tr_setup; } break; } }
static void uhso_ifnet_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct uhso_softc *sc = usbd_xfer_softc(xfer); struct mbuf *m; struct usb_page_cache *pc; int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); UHSO_DPRINTF(3, "status=%d, actlen=%d\n", USB_GET_STATE(xfer), actlen); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: if (actlen > 0 && (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)) { pc = usbd_xfer_get_frame(xfer, 0); m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); usbd_copy_out(pc, 0, mtod(m, uint8_t *), actlen); m->m_pkthdr.len = m->m_len = actlen; /* Enqueue frame for further processing */ _IF_ENQUEUE(&sc->sc_rxq, m); if (!callout_pending(&sc->sc_c) || !callout_active(&sc->sc_c)) { callout_schedule(&sc->sc_c, 1); } } /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); break; default: UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error)); if (error == USB_ERR_CANCELLED) break; usbd_xfer_set_stall(xfer); goto tr_setup; }
static void ugen_isoc_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct usb_fifo *f = usbd_xfer_softc(xfer); usb_frlength_t offset; usb_frcount_t n; DPRINTFN(4, "actlen=%u, aframes=%u\n", xfer->actlen, xfer->aframes); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(6, "actlen=%d\n", xfer->actlen); offset = 0; for (n = 0; n != xfer->aframes; n++) { usb_fifo_put_data(f, xfer->frbuffers, offset, xfer->frlengths[n], 1); offset += xfer->max_frame_size; } case USB_ST_SETUP: tr_setup: for (n = 0; n != xfer->nframes; n++) { /* setup size for next transfer */ usbd_xfer_set_frame_len(xfer, n, xfer->max_frame_size); } usbd_transfer_submit(xfer); break; default: /* Error */ if (xfer->error == USB_ERR_CANCELLED) { break; } goto tr_setup; } }
static void ugen_default_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct usb_fifo *f = usbd_xfer_softc(xfer); usb_frlength_t actlen; DPRINTFN(4, "actlen=%u, aframes=%u\n", xfer->actlen, xfer->aframes); switch (USB_GET_STATE(xfer)) { case USB_ST_SETUP: case USB_ST_TRANSFERRED: /* * If writing is in stall, just jump to clear stall * callback and solve the situation. */ if (f->flag_stall) { usbd_transfer_start(f->xfer[1]); break; } /* * Write data, setup and perform hardware transfer. */ if (usb_fifo_get_data(f, xfer->frbuffers, 0, xfer->max_data_length, &actlen, 0)) { usbd_xfer_set_frame_len(xfer, 0, actlen); usbd_transfer_submit(xfer); } break; default: /* Error */ if (xfer->error != USB_ERR_CANCELLED) { f->flag_stall = 1; usbd_transfer_start(f->xfer[1]); } break; } }
static void cdce_ncm_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct cdce_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0); struct ifnet *ifp = uether_getifp(&sc->sc_ue); struct mbuf *m; int sumdata; int sumlen; int actlen; int aframes; int temp; int nframes; int x; int offset; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: usbd_xfer_status(xfer, &actlen, &sumlen, &aframes, NULL); DPRINTFN(1, "received %u bytes in %u frames\n", actlen, aframes); if (actlen < (sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt))) { DPRINTFN(1, "frame too short\n"); goto tr_setup; } usbd_copy_out(pc, 0, &(sc->sc_ncm.hdr), sizeof(sc->sc_ncm.hdr)); if ((sc->sc_ncm.hdr.dwSignature[0] != 'N') || (sc->sc_ncm.hdr.dwSignature[1] != 'C') || (sc->sc_ncm.hdr.dwSignature[2] != 'M') || (sc->sc_ncm.hdr.dwSignature[3] != 'H')) { DPRINTFN(1, "invalid HDR signature: " "0x%02x:0x%02x:0x%02x:0x%02x\n", sc->sc_ncm.hdr.dwSignature[0], sc->sc_ncm.hdr.dwSignature[1], sc->sc_ncm.hdr.dwSignature[2], sc->sc_ncm.hdr.dwSignature[3]); goto tr_stall; } temp = UGETW(sc->sc_ncm.hdr.wBlockLength); if (temp > sumlen) { DPRINTFN(1, "unsupported block length %u/%u\n", temp, sumlen); goto tr_stall; } temp = UGETW(sc->sc_ncm.hdr.wDptIndex); if ((temp + sizeof(sc->sc_ncm.dpt)) > actlen) { DPRINTFN(1, "invalid DPT index: 0x%04x\n", temp); goto tr_stall; } usbd_copy_out(pc, temp, &(sc->sc_ncm.dpt), sizeof(sc->sc_ncm.dpt)); if ((sc->sc_ncm.dpt.dwSignature[0] != 'N') || (sc->sc_ncm.dpt.dwSignature[1] != 'C') || (sc->sc_ncm.dpt.dwSignature[2] != 'M') || (sc->sc_ncm.dpt.dwSignature[3] != '0')) { DPRINTFN(1, "invalid DPT signature" "0x%02x:0x%02x:0x%02x:0x%02x\n", sc->sc_ncm.dpt.dwSignature[0], sc->sc_ncm.dpt.dwSignature[1], sc->sc_ncm.dpt.dwSignature[2], sc->sc_ncm.dpt.dwSignature[3]); goto tr_stall; } nframes = UGETW(sc->sc_ncm.dpt.wLength) / 4; /* Subtract size of header and last zero padded entry */ if (nframes >= (2 + 1)) nframes -= (2 + 1); else nframes = 0; DPRINTFN(1, "nframes = %u\n", nframes); temp += sizeof(sc->sc_ncm.dpt); if ((temp + (4 * nframes)) > actlen) goto tr_stall; if (nframes > CDCE_NCM_SUBFRAMES_MAX) { DPRINTFN(1, "Truncating number of frames from %u to %u\n", nframes, CDCE_NCM_SUBFRAMES_MAX); nframes = CDCE_NCM_SUBFRAMES_MAX; } usbd_copy_out(pc, temp, &(sc->sc_ncm.dp), (4 * nframes)); sumdata = 0; for (x = 0; x != nframes; x++) { offset = UGETW(sc->sc_ncm.dp[x].wFrameIndex); temp = UGETW(sc->sc_ncm.dp[x].wFrameLength); if ((offset == 0) || (temp < sizeof(struct ether_header)) || (temp > (MCLBYTES - ETHER_ALIGN))) { DPRINTFN(1, "NULL frame detected at %d\n", x); m = NULL; /* silently ignore this frame */ continue; } else if ((offset + temp) > actlen) { DPRINTFN(1, "invalid frame " "detected at %d\n", x); m = NULL; /* silently ignore this frame */ continue; } else if (temp > (MHLEN - ETHER_ALIGN)) { m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); } else { m = m_gethdr(M_DONTWAIT, MT_DATA); } DPRINTFN(16, "frame %u, offset = %u, length = %u \n", x, offset, temp); /* check if we have a buffer */ if (m) { m_adj(m, ETHER_ALIGN); usbd_copy_out(pc, offset, m->m_data, temp); /* enqueue */ uether_rxmbuf(&sc->sc_ue, m, temp); sumdata += temp; } else { ifp->if_ierrors++; } } DPRINTFN(1, "Efficiency: %u/%u bytes\n", sumdata, actlen); case USB_ST_SETUP: tr_setup: usbd_xfer_set_frame_len(xfer, 0, sc->sc_ncm.rx_max); usbd_xfer_set_frames(xfer, 1); usbd_transfer_submit(xfer); uether_rxflush(&sc->sc_ue); /* must be last */ break; default: /* Error */ DPRINTFN(1, "error = %s\n", usbd_errstr(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); } break; } }
static int ugen_fs_copy_in(struct usb_fifo *f, uint8_t ep_index) { struct usb_device_request *req; struct usb_xfer *xfer; struct usb_fs_endpoint fs_ep; void *uaddr; /* userland pointer */ void *kaddr; usb_frlength_t offset; usb_frlength_t rem; usb_frcount_t n; uint32_t length; int error; uint8_t isread; if (ep_index >= f->fs_ep_max) { return (EINVAL); } xfer = f->fs_xfer[ep_index]; if (xfer == NULL) { return (EINVAL); } mtx_lock(f->priv_mtx); if (usbd_transfer_pending(xfer)) { mtx_unlock(f->priv_mtx); return (EBUSY); /* should not happen */ } mtx_unlock(f->priv_mtx); error = copyin(f->fs_ep_ptr + ep_index, &fs_ep, sizeof(fs_ep)); if (error) { return (error); } /* security checks */ if (fs_ep.nFrames > xfer->max_frame_count) { xfer->error = USB_ERR_INVAL; goto complete; } if (fs_ep.nFrames == 0) { xfer->error = USB_ERR_INVAL; goto complete; } error = copyin(fs_ep.ppBuffer, &uaddr, sizeof(uaddr)); if (error) { return (error); } /* reset first frame */ usbd_xfer_set_frame_offset(xfer, 0, 0); if (xfer->flags_int.control_xfr) { req = xfer->frbuffers[0].buffer; error = copyin(fs_ep.pLength, &length, sizeof(length)); if (error) { return (error); } if (length != sizeof(*req)) { xfer->error = USB_ERR_INVAL; goto complete; } if (length != 0) { error = copyin(uaddr, req, length); if (error) { return (error); } } if (ugen_check_request(f->udev, req)) { xfer->error = USB_ERR_INVAL; goto complete; } usbd_xfer_set_frame_len(xfer, 0, length); /* Host mode only ! */ if ((req->bmRequestType & (UT_READ | UT_WRITE)) == UT_READ) { isread = 1; } else { isread = 0; } n = 1; offset = sizeof(*req); } else { /* Device and Host mode */ if (USB_GET_DATA_ISREAD(xfer)) { isread = 1; } else { isread = 0; } n = 0; offset = 0; } rem = usbd_xfer_max_len(xfer); xfer->nframes = fs_ep.nFrames; xfer->timeout = fs_ep.timeout; if (xfer->timeout > 65535) { xfer->timeout = 65535; } if (fs_ep.flags & USB_FS_FLAG_SINGLE_SHORT_OK) xfer->flags.short_xfer_ok = 1; else xfer->flags.short_xfer_ok = 0; if (fs_ep.flags & USB_FS_FLAG_MULTI_SHORT_OK) xfer->flags.short_frames_ok = 1; else xfer->flags.short_frames_ok = 0; if (fs_ep.flags & USB_FS_FLAG_FORCE_SHORT) xfer->flags.force_short_xfer = 1; else xfer->flags.force_short_xfer = 0; if (fs_ep.flags & USB_FS_FLAG_CLEAR_STALL) usbd_xfer_set_stall(xfer); else xfer->flags.stall_pipe = 0; for (; n != xfer->nframes; n++) { error = copyin(fs_ep.pLength + n, &length, sizeof(length)); if (error) { break; } usbd_xfer_set_frame_len(xfer, n, length); if (length > rem) { xfer->error = USB_ERR_INVAL; goto complete; } rem -= length; if (!isread) { /* we need to know the source buffer */ error = copyin(fs_ep.ppBuffer + n, &uaddr, sizeof(uaddr)); if (error) { break; } if (xfer->flags_int.isochronous_xfr) { /* get kernel buffer address */ kaddr = xfer->frbuffers[0].buffer; kaddr = USB_ADD_BYTES(kaddr, offset); } else { /* set current frame offset */ usbd_xfer_set_frame_offset(xfer, offset, n); /* get kernel buffer address */ kaddr = xfer->frbuffers[n].buffer; } /* move data */ error = copyin(uaddr, kaddr, length); if (error) { break; } } offset += length; } return (error); complete: mtx_lock(f->priv_mtx); ugen_fs_set_complete(f, ep_index); mtx_unlock(f->priv_mtx); return (0); }
static void usbd_non_isoc_callback(struct usb_xfer *xfer, usb_error_t error) { irp *ip; struct ndis_softc *sc = usbd_xfer_softc(xfer); struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer); struct ndisusb_xfer *nx; struct usbd_urb_bulk_or_intr_transfer *ubi; struct usb_page_cache *pc; uint8_t irql; uint32_t len; union usbd_urb *urb; usb_endpoint_descriptor_t *ep; int actlen, sumlen; usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: nx = usbd_aq_getfirst(sc, ne); pc = usbd_xfer_get_frame(xfer, 0); if (nx == NULL) return; /* copy in data with regard to the URB */ if (ne->ne_dirin != 0) usbd_copy_out(pc, 0, nx->nx_urbbuf, actlen); nx->nx_urbbuf += actlen; nx->nx_urbactlen += actlen; nx->nx_urblen -= actlen; /* check for short transfer */ if (actlen < sumlen) nx->nx_urblen = 0; else { /* check remainder */ if (nx->nx_urblen > 0) { KeAcquireSpinLock(&ne->ne_lock, &irql); InsertHeadList((&ne->ne_active), (&nx->nx_next)); KeReleaseSpinLock(&ne->ne_lock, irql); ip = nx->nx_priv; urb = usbd_geturb(ip); ubi = &urb->uu_bulkintr; ep = ubi->ubi_epdesc; goto extra; } } usbd_xfer_complete(sc, ne, nx, ((actlen < sumlen) && (nx->nx_shortxfer == 0)) ? USB_ERR_SHORT_XFER : USB_ERR_NORMAL_COMPLETION); /* fall through */ case USB_ST_SETUP: next: /* get next transfer */ KeAcquireSpinLock(&ne->ne_lock, &irql); if (IsListEmpty(&ne->ne_pending)) { KeReleaseSpinLock(&ne->ne_lock, irql); return; } nx = CONTAINING_RECORD(ne->ne_pending.nle_flink, struct ndisusb_xfer, nx_next); RemoveEntryList(&nx->nx_next); /* add a entry to the active queue's tail. */ InsertTailList((&ne->ne_active), (&nx->nx_next)); KeReleaseSpinLock(&ne->ne_lock, irql); ip = nx->nx_priv; urb = usbd_geturb(ip); ubi = &urb->uu_bulkintr; ep = ubi->ubi_epdesc; nx->nx_urbbuf = ubi->ubi_trans_buf; nx->nx_urbactlen = 0; nx->nx_urblen = ubi->ubi_trans_buflen; nx->nx_shortxfer = (ubi->ubi_trans_flags & USBD_SHORT_TRANSFER_OK) ? 1 : 0; extra: len = MIN(usbd_xfer_max_len(xfer), nx->nx_urblen); pc = usbd_xfer_get_frame(xfer, 0); if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT) usbd_copy_in(pc, 0, nx->nx_urbbuf, len); usbd_xfer_set_frame_len(xfer, 0, len); usbd_xfer_set_frames(xfer, 1); usbd_transfer_submit(xfer); break; default: nx = usbd_aq_getfirst(sc, ne); if (nx == NULL) return; if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); device_printf(sc->ndis_dev, "usb xfer warning (%s)\n", usbd_errstr(error)); } usbd_xfer_complete(sc, ne, nx, error); if (error != USB_ERR_CANCELLED) goto next; break; } }
/*------------------------------------------------------------------------* * usb_handle_request * * Internal state sequence: * * USB_HR_NOT_COMPLETE -> USB_HR_COMPLETE_OK v USB_HR_COMPLETE_ERR * * Returns: * 0: Ready to start hardware * Else: Stall current transfer, if any *------------------------------------------------------------------------*/ static usb_error_t usb_handle_request(struct usb_xfer *xfer) { struct usb_device_request req; struct usb_device *udev; const void *src_zcopy; /* zero-copy source pointer */ const void *src_mcopy; /* non zero-copy source pointer */ uint16_t off; /* data offset */ uint16_t rem; /* data remainder */ uint16_t max_len; /* max fragment length */ uint16_t wValue; uint16_t wIndex; uint8_t state; uint8_t is_complete = 1; usb_error_t err; union { uWord wStatus; uint8_t buf[2]; } temp; /* * Filter the USB transfer state into * something which we understand: */ switch (USB_GET_STATE(xfer)) { case USB_ST_SETUP: state = USB_HR_NOT_COMPLETE; if (!xfer->flags_int.control_act) { /* nothing to do */ goto tr_stalled; } break; case USB_ST_TRANSFERRED: if (!xfer->flags_int.control_act) { state = USB_HR_COMPLETE_OK; } else { state = USB_HR_NOT_COMPLETE; } break; default: state = USB_HR_COMPLETE_ERR; break; } /* reset frame stuff */ usbd_xfer_set_frame_len(xfer, 0, 0); usbd_xfer_set_frame_offset(xfer, 0, 0); usbd_xfer_set_frame_offset(xfer, sizeof(req), 1); /* get the current request, if any */ usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req)); if (xfer->flags_int.control_rem == 0xFFFF) { /* first time - not initialised */ rem = UGETW(req.wLength); off = 0; } else { /* not first time - initialised */ rem = xfer->flags_int.control_rem; off = UGETW(req.wLength) - rem; } /* set some defaults */ max_len = 0; src_zcopy = NULL; src_mcopy = NULL; udev = xfer->xroot->udev; /* get some request fields decoded */ wValue = UGETW(req.wValue); wIndex = UGETW(req.wIndex); DPRINTF("req 0x%02x 0x%02x 0x%04x 0x%04x " "off=0x%x rem=0x%x, state=%d\n", req.bmRequestType, req.bRequest, wValue, wIndex, off, rem, state); /* demultiplex the control request */ switch (req.bmRequestType) { case UT_READ_DEVICE: if (state != USB_HR_NOT_COMPLETE) { break; } switch (req.bRequest) { case UR_GET_DESCRIPTOR: goto tr_handle_get_descriptor; case UR_GET_CONFIG: goto tr_handle_get_config; case UR_GET_STATUS: goto tr_handle_get_status; default: goto tr_stalled; } break; case UT_WRITE_DEVICE: switch (req.bRequest) { case UR_SET_ADDRESS: goto tr_handle_set_address; case UR_SET_CONFIG: goto tr_handle_set_config; case UR_CLEAR_FEATURE: switch (wValue) { case UF_DEVICE_REMOTE_WAKEUP: goto tr_handle_clear_wakeup; default: goto tr_stalled; } break; case UR_SET_FEATURE: switch (wValue) { case UF_DEVICE_REMOTE_WAKEUP: goto tr_handle_set_wakeup; default: goto tr_stalled; } break; default: goto tr_stalled; } break; case UT_WRITE_ENDPOINT: switch (req.bRequest) { case UR_CLEAR_FEATURE: switch (wValue) { case UF_ENDPOINT_HALT: goto tr_handle_clear_halt; default: goto tr_stalled; } break; case UR_SET_FEATURE: switch (wValue) { case UF_ENDPOINT_HALT: goto tr_handle_set_halt; default: goto tr_stalled; } break; default: goto tr_stalled; } break; case UT_READ_ENDPOINT: switch (req.bRequest) { case UR_GET_STATUS: goto tr_handle_get_ep_status; default: goto tr_stalled; } break; default: /* we use "USB_ADD_BYTES" to de-const the src_zcopy */ err = usb_handle_iface_request(xfer, USB_ADD_BYTES(&src_zcopy, 0), &max_len, req, off, state); if (err == 0) { is_complete = 0; goto tr_valid; } else if (err == USB_ERR_SHORT_XFER) { goto tr_valid; } /* * Reset zero-copy pointer and max length * variable in case they were unintentionally * set: */ src_zcopy = NULL; max_len = 0; /* * Check if we have a vendor specific * descriptor: */ goto tr_handle_get_descriptor; } goto tr_valid; tr_handle_get_descriptor: err = (usb_temp_get_desc_p) (udev, &req, &src_zcopy, &max_len); if (err) goto tr_stalled; if (src_zcopy == NULL) goto tr_stalled; goto tr_valid; tr_handle_get_config: temp.buf[0] = udev->curr_config_no; src_mcopy = temp.buf; max_len = 1; goto tr_valid; tr_handle_get_status: wValue = 0; USB_BUS_LOCK(udev->bus); if (udev->flags.remote_wakeup) { wValue |= UDS_REMOTE_WAKEUP; } if (udev->flags.self_powered) { wValue |= UDS_SELF_POWERED; } USB_BUS_UNLOCK(udev->bus); USETW(temp.wStatus, wValue); src_mcopy = temp.wStatus; max_len = sizeof(temp.wStatus); goto tr_valid; tr_handle_set_address: if (state == USB_HR_NOT_COMPLETE) { if (wValue >= 0x80) { /* invalid value */ goto tr_stalled; } else if (udev->curr_config_no != 0) { /* we are configured ! */ goto tr_stalled; } } else if (state != USB_HR_NOT_COMPLETE) { udev->address = (wValue & 0x7F); goto tr_bad_context; } goto tr_valid; tr_handle_set_config: if (state == USB_HR_NOT_COMPLETE) { if (usb_handle_set_config(xfer, req.wValue[0])) { goto tr_stalled; } } goto tr_valid; tr_handle_clear_halt: if (state == USB_HR_NOT_COMPLETE) { if (usb_handle_set_stall(xfer, req.wIndex[0], 0)) { goto tr_stalled; } } goto tr_valid; tr_handle_clear_wakeup: if (state == USB_HR_NOT_COMPLETE) { if (usb_handle_remote_wakeup(xfer, 0)) { goto tr_stalled; } } goto tr_valid; tr_handle_set_halt: if (state == USB_HR_NOT_COMPLETE) { if (usb_handle_set_stall(xfer, req.wIndex[0], 1)) { goto tr_stalled; } } goto tr_valid; tr_handle_set_wakeup: if (state == USB_HR_NOT_COMPLETE) { if (usb_handle_remote_wakeup(xfer, 1)) { goto tr_stalled; } } goto tr_valid; tr_handle_get_ep_status: if (state == USB_HR_NOT_COMPLETE) { temp.wStatus[0] = usb_handle_get_stall(udev, req.wIndex[0]); temp.wStatus[1] = 0; src_mcopy = temp.wStatus; max_len = sizeof(temp.wStatus); } goto tr_valid; tr_valid: if (state != USB_HR_NOT_COMPLETE) { goto tr_stalled; } /* subtract offset from length */ max_len -= off; /* Compute the real maximum data length */ if (max_len > xfer->max_data_length) { max_len = usbd_xfer_max_len(xfer); } if (max_len > rem) { max_len = rem; } /* * If the remainder is greater than the maximum data length, * we need to truncate the value for the sake of the * comparison below: */ if (rem > xfer->max_data_length) { rem = usbd_xfer_max_len(xfer); } if ((rem != max_len) && (is_complete != 0)) { /* * If we don't transfer the data we can transfer, then * the transfer is short ! */ xfer->flags.force_short_xfer = 1; xfer->nframes = 2; } else { /* * Default case */ xfer->flags.force_short_xfer = 0; xfer->nframes = max_len ? 2 : 1; } if (max_len > 0) { if (src_mcopy) { src_mcopy = USB_ADD_BYTES(src_mcopy, off); usbd_copy_in(xfer->frbuffers + 1, 0, src_mcopy, max_len); usbd_xfer_set_frame_len(xfer, 1, max_len); } else { usbd_xfer_set_frame_data(xfer, 1, USB_ADD_BYTES(src_zcopy, off), max_len); } } else { /* the end is reached, send status */ xfer->flags.manual_status = 0; usbd_xfer_set_frame_len(xfer, 1, 0); } DPRINTF("success\n"); return (0); /* success */ tr_stalled: DPRINTF("%s\n", (state != USB_HR_NOT_COMPLETE) ? "complete" : "stalled"); return (USB_ERR_STALLED); tr_bad_context: DPRINTF("bad context\n"); return (USB_ERR_BAD_CONTEXT); }
static void ubt_ctrl_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct ubt_softc *sc = usbd_xfer_softc(xfer); struct usb_device_request req; struct mbuf *m; struct usb_page_cache *pc; int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: UBT_INFO(sc, "sent %d bytes to control pipe\n", actlen); UBT_STAT_BYTES_SENT(sc, actlen); UBT_STAT_PCKTS_SENT(sc); /* FALLTHROUGH */ case USB_ST_SETUP: send_next: /* Get next command mbuf, if any */ UBT_NG_LOCK(sc); NG_BT_MBUFQ_DEQUEUE(&sc->sc_cmdq, m); UBT_NG_UNLOCK(sc); if (m == NULL) { UBT_INFO(sc, "HCI command queue is empty\n"); break; /* transfer complete */ } /* Initialize a USB control request and then schedule it */ bzero(&req, sizeof(req)); req.bmRequestType = UBT_HCI_REQUEST; USETW(req.wLength, m->m_pkthdr.len); UBT_INFO(sc, "Sending control request, " \ "bmRequestType=0x%02x, wLength=%d\n", req.bmRequestType, UGETW(req.wLength)); pc = usbd_xfer_get_frame(xfer, 0); usbd_copy_in(pc, 0, &req, sizeof(req)); pc = usbd_xfer_get_frame(xfer, 1); usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); usbd_xfer_set_frame_len(xfer, 1, m->m_pkthdr.len); usbd_xfer_set_frames(xfer, 2); NG_FREE_M(m); usbd_transfer_submit(xfer); break; default: /* Error */ if (error != USB_ERR_CANCELLED) { UBT_WARN(sc, "control transfer failed: %s\n", usbd_errstr(error)); UBT_STAT_OERROR(sc); goto send_next; } /* transfer cancelled */ break; } } /* ubt_ctrl_write_callback */
static void ubt_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) { struct ubt_softc *sc = usbd_xfer_softc(xfer); struct mbuf *m; ng_hci_acldata_pkt_t *hdr; struct usb_page_cache *pc; int len; int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); m = NULL; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: /* Allocate new mbuf */ MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) { UBT_STAT_IERROR(sc); goto submit_next; } if (!(MCLGET(m, M_NOWAIT))) { UBT_STAT_IERROR(sc); goto submit_next; } /* Add HCI packet type */ *mtod(m, uint8_t *)= NG_HCI_ACL_DATA_PKT; m->m_pkthdr.len = m->m_len = 1; if (actlen > MCLBYTES - 1) actlen = MCLBYTES - 1; pc = usbd_xfer_get_frame(xfer, 0); usbd_copy_out(pc, 0, mtod(m, uint8_t *) + 1, actlen); m->m_pkthdr.len += actlen; m->m_len += actlen; UBT_INFO(sc, "got %d bytes from bulk-in pipe\n", actlen); /* Validate packet and send it up the stack */ if (m->m_pkthdr.len < (int)sizeof(*hdr)) { UBT_INFO(sc, "HCI ACL packet is too short\n"); UBT_STAT_IERROR(sc); goto submit_next; } hdr = mtod(m, ng_hci_acldata_pkt_t *); len = le16toh(hdr->length); if (len != (int)(m->m_pkthdr.len - sizeof(*hdr))) { UBT_ERR(sc, "Invalid ACL packet size, length=%d, " \ "pktlen=%d\n", len, m->m_pkthdr.len); UBT_STAT_IERROR(sc); goto submit_next; } UBT_INFO(sc, "got complete ACL data packet, pktlen=%d, " \ "length=%d\n", m->m_pkthdr.len, len); UBT_STAT_PCKTS_RECV(sc); UBT_STAT_BYTES_RECV(sc, m->m_pkthdr.len); ubt_fwd_mbuf_up(sc, &m); /* m == NULL at this point */ /* FALLTHOUGH */ case USB_ST_SETUP: submit_next: NG_FREE_M(m); /* checks for m != NULL */ usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); usbd_transfer_submit(xfer); break; default: /* Error */ if (error != USB_ERR_CANCELLED) { UBT_WARN(sc, "bulk-in transfer failed: %s\n", usbd_errstr(error)); /* Try to clear stall first */ usbd_xfer_set_stall(xfer); goto submit_next; } /* transfer cancelled */ break; } } /* ubt_bulk_read_callback */
static uint8_t cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) { struct cdce_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = uether_getifp(&sc->sc_ue); struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, index); struct mbuf *m; uint32_t rem; uint32_t offset; uint32_t last_offset; uint16_t n; uint8_t retval; usbd_xfer_set_frame_offset(xfer, index * CDCE_NCM_TX_MAXLEN, index); offset = sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt) + sizeof(sc->sc_ncm.dp); /* Store last valid offset before alignment */ last_offset = offset; /* Align offset */ offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder, offset, sc->sc_ncm.tx_modulus); /* Zero pad */ cdce_ncm_tx_zero(pc, last_offset, offset); /* buffer full */ retval = 2; for (n = 0; n != sc->sc_ncm.tx_nframe; n++) { /* check if end of transmit buffer is reached */ if (offset >= sc->sc_ncm.tx_max) break; /* compute maximum buffer size */ rem = sc->sc_ncm.tx_max - offset; IFQ_DRV_DEQUEUE(&(ifp->if_snd), m); if (m == NULL) { /* buffer not full */ retval = 1; break; } if (m->m_pkthdr.len > rem) { if (n == 0) { /* The frame won't fit in our buffer */ DPRINTFN(1, "Frame too big to be transmitted!\n"); m_freem(m); ifp->if_oerrors++; n--; continue; } /* Wait till next buffer becomes ready */ IFQ_DRV_PREPEND(&(ifp->if_snd), m); break; } usbd_m_copy_in(pc, offset, m, 0, m->m_pkthdr.len); USETW(sc->sc_ncm.dp[n].wFrameLength, m->m_pkthdr.len); USETW(sc->sc_ncm.dp[n].wFrameIndex, offset); /* Update offset */ offset += m->m_pkthdr.len; /* Store last valid offset before alignment */ last_offset = offset; /* Align offset */ offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder, offset, sc->sc_ncm.tx_modulus); /* Zero pad */ cdce_ncm_tx_zero(pc, last_offset, offset); /* * If there's a BPF listener, bounce a copy * of this frame to him: */ BPF_MTAP(ifp, m); /* Free mbuf */ m_freem(m); /* Pre-increment interface counter */ ifp->if_opackets++; } if (n == 0) return (0); rem = (sizeof(sc->sc_ncm.dpt) + (4 * n) + 4); USETW(sc->sc_ncm.dpt.wLength, rem); /* zero the rest of the data pointer entries */ for (; n != CDCE_NCM_SUBFRAMES_MAX; n++) { USETW(sc->sc_ncm.dp[n].wFrameLength, 0); USETW(sc->sc_ncm.dp[n].wFrameIndex, 0); } offset = last_offset; /* Align offset */ offset = CDCE_NCM_ALIGN(0, offset, CDCE_NCM_TX_MINLEN); /* Optimise, save bandwidth and force short termination */ if (offset >= sc->sc_ncm.tx_max) offset = sc->sc_ncm.tx_max; else offset ++; /* Zero pad */ cdce_ncm_tx_zero(pc, last_offset, offset); /* set frame length */ usbd_xfer_set_frame_len(xfer, index, offset); /* Fill out 16-bit header */ sc->sc_ncm.hdr.dwSignature[0] = 'N'; sc->sc_ncm.hdr.dwSignature[1] = 'C'; sc->sc_ncm.hdr.dwSignature[2] = 'M'; sc->sc_ncm.hdr.dwSignature[3] = 'H'; USETW(sc->sc_ncm.hdr.wHeaderLength, sizeof(sc->sc_ncm.hdr)); USETW(sc->sc_ncm.hdr.wBlockLength, offset); USETW(sc->sc_ncm.hdr.wSequence, sc->sc_ncm.tx_seq); USETW(sc->sc_ncm.hdr.wDptIndex, sizeof(sc->sc_ncm.hdr)); sc->sc_ncm.tx_seq++; /* Fill out 16-bit frame table header */ sc->sc_ncm.dpt.dwSignature[0] = 'N'; sc->sc_ncm.dpt.dwSignature[1] = 'C'; sc->sc_ncm.dpt.dwSignature[2] = 'M'; sc->sc_ncm.dpt.dwSignature[3] = '0'; USETW(sc->sc_ncm.dpt.wNextNdpIndex, 0); /* reserved */ usbd_copy_in(pc, 0, &(sc->sc_ncm.hdr), sizeof(sc->sc_ncm.hdr)); usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr), &(sc->sc_ncm.dpt), sizeof(sc->sc_ncm.dpt)); usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt), &(sc->sc_ncm.dp), sizeof(sc->sc_ncm.dp)); return (retval); }
static void usie_if_tx_callback(struct usb_xfer *xfer, usb_error_t error) { struct usie_softc *sc = usbd_xfer_softc(xfer); struct usb_page_cache *pc; struct ifnet *ifp = sc->sc_ifp; struct mbuf *m; uint16_t size; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(11, "transfer complete\n"); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp->if_opackets++; /* fall though */ case USB_ST_SETUP: tr_setup: if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) break; IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) break; if (m->m_pkthdr.len > (MCLBYTES - ETHER_HDR_LEN + ETHER_CRC_LEN - sizeof(sc->sc_txd))) { DPRINTF("packet len is too big: %d\n", m->m_pkthdr.len); break; } pc = usbd_xfer_get_frame(xfer, 0); sc->sc_txd.hip.len = htobe16(m->m_pkthdr.len + ETHER_HDR_LEN + ETHER_CRC_LEN); size = sizeof(sc->sc_txd); usbd_copy_in(pc, 0, &sc->sc_txd, size); usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len); usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len + size + ETHER_CRC_LEN); BPF_MTAP(ifp, m); m_freem(m); usbd_transfer_submit(xfer); break; default: /* Error */ DPRINTF("USB transfer error, %s\n", usbd_errstr(error)); ifp->if_oerrors++; if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); ifp->if_ierrors++; goto tr_setup; } break; } }
static void ipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct ipheth_softc *sc = usbd_xfer_softc(xfer); struct ifnet *ifp = uether_getifp(&sc->sc_ue); struct usb_page_cache *pc; struct mbuf *m; uint8_t x; int actlen; int aframes; usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); DPRINTFN(1, "\n"); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: DPRINTFN(11, "transfer complete: %u bytes in %u frames\n", actlen, aframes); ifp->if_opackets++; /* free all previous TX buffers */ ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); /* FALLTHROUGH */ case USB_ST_SETUP: tr_setup: for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) break; usbd_xfer_set_frame_offset(xfer, x * IPHETH_BUF_SIZE, x); pc = usbd_xfer_get_frame(xfer, x); sc->sc_tx_buf[x] = m; if (m->m_pkthdr.len > IPHETH_BUF_SIZE) m->m_pkthdr.len = IPHETH_BUF_SIZE; usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE); if (IPHETH_BUF_SIZE != m->m_pkthdr.len) { usbd_frame_zero(pc, m->m_pkthdr.len, IPHETH_BUF_SIZE - m->m_pkthdr.len); } /* * If there's a BPF listener, bounce a copy of * this frame to him: */ BPF_MTAP(ifp, m); } if (x != 0) { usbd_xfer_set_frames(xfer, x); usbd_transfer_submit(xfer); } break; default: /* Error */ DPRINTFN(11, "transfer error, %s\n", usbd_errstr(error)); /* free all previous TX buffers */ ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); /* count output errors */ ifp->if_oerrors++; if (error != USB_ERR_CANCELLED) { /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto tr_setup; } break; } }
static void ubt_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) { struct ubt_softc *sc = usbd_xfer_softc(xfer); struct mbuf *m; struct usb_page_cache *pc; int actlen; usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: UBT_INFO(sc, "sent %d bytes to bulk-out pipe\n", actlen); UBT_STAT_BYTES_SENT(sc, actlen); UBT_STAT_PCKTS_SENT(sc); /* FALLTHROUGH */ case USB_ST_SETUP: send_next: /* Get next mbuf, if any */ UBT_NG_LOCK(sc); NG_BT_MBUFQ_DEQUEUE(&sc->sc_aclq, m); UBT_NG_UNLOCK(sc); if (m == NULL) { UBT_INFO(sc, "ACL data queue is empty\n"); break; /* transfer completed */ } /* * Copy ACL data frame back to a linear USB transfer buffer * and schedule transfer */ pc = usbd_xfer_get_frame(xfer, 0); usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len); UBT_INFO(sc, "bulk-out transfer has been started, len=%d\n", m->m_pkthdr.len); NG_FREE_M(m); usbd_transfer_submit(xfer); break; default: /* Error */ if (error != USB_ERR_CANCELLED) { UBT_WARN(sc, "bulk-out transfer failed: %s\n", usbd_errstr(error)); UBT_STAT_OERROR(sc); /* try to clear stall first */ usbd_xfer_set_stall(xfer); goto send_next; } /* transfer cancelled */ break; } } /* ubt_bulk_write_callback */
static void usbd_ctrl_callback(struct usb_xfer *xfer, usb_error_t error) { irp *ip; struct ndis_softc *sc = usbd_xfer_softc(xfer); struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer); struct ndisusb_xfer *nx; uint8_t irql; union usbd_urb *urb; struct usbd_urb_vendor_or_class_request *vcreq; struct usb_page_cache *pc; uint8_t type = 0; struct usb_device_request req; int len; switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: nx = usbd_aq_getfirst(sc, ne); if (nx == NULL) return; ip = nx->nx_priv; urb = usbd_geturb(ip); vcreq = &urb->uu_vcreq; if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) { pc = usbd_xfer_get_frame(xfer, 1); len = usbd_xfer_frame_len(xfer, 1); usbd_copy_out(pc, 0, vcreq->uvc_trans_buf, len); nx->nx_urbactlen += len; } usbd_xfer_complete(sc, ne, nx, USB_ERR_NORMAL_COMPLETION); /* fall through */ case USB_ST_SETUP: next: /* get next transfer */ KeAcquireSpinLock(&ne->ne_lock, &irql); if (IsListEmpty(&ne->ne_pending)) { KeReleaseSpinLock(&ne->ne_lock, irql); return; } nx = CONTAINING_RECORD(ne->ne_pending.nle_flink, struct ndisusb_xfer, nx_next); RemoveEntryList(&nx->nx_next); /* add a entry to the active queue's tail. */ InsertTailList((&ne->ne_active), (&nx->nx_next)); KeReleaseSpinLock(&ne->ne_lock, irql); ip = nx->nx_priv; urb = usbd_geturb(ip); vcreq = &urb->uu_vcreq; switch (urb->uu_hdr.uuh_func) { case URB_FUNCTION_CLASS_DEVICE: type = UT_CLASS | UT_DEVICE; break; case URB_FUNCTION_CLASS_INTERFACE: type = UT_CLASS | UT_INTERFACE; break; case URB_FUNCTION_CLASS_OTHER: type = UT_CLASS | UT_OTHER; break; case URB_FUNCTION_CLASS_ENDPOINT: type = UT_CLASS | UT_ENDPOINT; break; case URB_FUNCTION_VENDOR_DEVICE: type = UT_VENDOR | UT_DEVICE; break; case URB_FUNCTION_VENDOR_INTERFACE: type = UT_VENDOR | UT_INTERFACE; break; case URB_FUNCTION_VENDOR_OTHER: type = UT_VENDOR | UT_OTHER; break; case URB_FUNCTION_VENDOR_ENDPOINT: type = UT_VENDOR | UT_ENDPOINT; break; default: /* never reached. */ break; } type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ? UT_READ : UT_WRITE; type |= vcreq->uvc_reserved1; req.bmRequestType = type; req.bRequest = vcreq->uvc_req; USETW(req.wIndex, vcreq->uvc_idx); USETW(req.wValue, vcreq->uvc_value); USETW(req.wLength, vcreq->uvc_trans_buflen); nx->nx_urbbuf = vcreq->uvc_trans_buf; nx->nx_urblen = vcreq->uvc_trans_buflen; nx->nx_urbactlen = 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); if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) { if (vcreq->uvc_trans_buflen >= USBD_CTRL_READ_BUFFER_SP) device_printf(sc->ndis_dev, "warning: not enough buffer space (%d).\n", vcreq->uvc_trans_buflen); usbd_xfer_set_frame_len(xfer, 1, MIN(usbd_xfer_max_len(xfer), vcreq->uvc_trans_buflen)); usbd_xfer_set_frames(xfer, 2); } else { if (nx->nx_urblen > USBD_CTRL_WRITE_BUFFER_SP) device_printf(sc->ndis_dev, "warning: not enough write buffer space" " (%d).\n", nx->nx_urblen); /* * XXX with my local tests there was no cases to require * a extra buffer until now but it'd need to update in * the future if it needs to be. */ if (nx->nx_urblen > 0) { pc = usbd_xfer_get_frame(xfer, 1); usbd_copy_in(pc, 0, nx->nx_urbbuf, nx->nx_urblen); usbd_xfer_set_frame_len(xfer, 1, nx->nx_urblen); usbd_xfer_set_frames(xfer, 2); } } usbd_transfer_submit(xfer); break; default: nx = usbd_aq_getfirst(sc, ne); if (nx == NULL) return; if (error != USB_ERR_CANCELLED) { usbd_xfer_set_stall(xfer); device_printf(sc->ndis_dev, "usb xfer warning (%s)\n", usbd_errstr(error)); } usbd_xfer_complete(sc, ne, nx, error); if (error != USB_ERR_CANCELLED) goto next; break; } }