Esempio n. 1
0
static void
g_modem_timeout_reset(struct g_modem_softc *sc)
{
	int i = g_modem_pattern_interval;

	sc->sc_tx_interval = i;

	if (i <= 0)
		i = 1;
	else if (i > 1023)
		i = 1023;

	i = USB_MS_TO_TICKS(i);

	usb_callout_reset(&sc->sc_callout, i, &g_modem_timeout, sc);
}
Esempio n. 2
0
static int
usie_do_request(struct usie_softc *sc, struct usb_device_request *req,
    void *data)
{
	int err = 0;
	int ntries;

	mtx_assert(&sc->sc_mtx, MA_OWNED);

	for (ntries = 0; ntries != 10; ntries++) {
		err = usbd_do_request(sc->sc_udev,
		    &sc->sc_mtx, req, data);
		if (err == 0)
			break;

		DPRINTF("Control request failed: %s %d/10\n",
		    usbd_errstr(err), ntries);

		usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(10));
	}
	return (err);
}
/*------------------------------------------------------------------------*
 *	usbd_req_reset_port
 *
 * This function will instruct an USB HUB to perform a reset sequence
 * on the specified port number.
 *
 * Returns:
 *    0: Success. The USB device should now be at address zero.
 * Else: Failure. No USB device is present and the USB port should be
 *       disabled.
 *------------------------------------------------------------------------*/
usb_error_t
usbd_req_reset_port(struct usb_device *udev, struct mtx *mtx, uint8_t port)
{
	struct usb_port_status ps;
	usb_error_t err;
	uint16_t n;

#if USB_DEBUG
	uint16_t pr_poll_delay;
	uint16_t pr_recovery_delay;

#endif
	err = usbd_req_set_port_feature(udev, mtx, port, UHF_PORT_RESET);
	if (err) {
		goto done;
	}
#if USB_DEBUG
	/* range check input parameters */
	pr_poll_delay = usb_pr_poll_delay;
	if (pr_poll_delay < 1) {
		pr_poll_delay = 1;
	} else if (pr_poll_delay > 1000) {
		pr_poll_delay = 1000;
	}
	pr_recovery_delay = usb_pr_recovery_delay;
	if (pr_recovery_delay > 1000) {
		pr_recovery_delay = 1000;
	}
#endif
	n = 0;
	while (1) {
#if USB_DEBUG
		/* wait for the device to recover from reset */
		usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_poll_delay));
		n += pr_poll_delay;
#else
		/* wait for the device to recover from reset */
		usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_DELAY));
		n += USB_PORT_RESET_DELAY;
#endif
		err = usbd_req_get_port_status(udev, mtx, &ps, port);
		if (err) {
			goto done;
		}
		/* if the device disappeared, just give up */
		if (!(UGETW(ps.wPortStatus) & UPS_CURRENT_CONNECT_STATUS)) {
			goto done;
		}
		/* check if reset is complete */
		if (UGETW(ps.wPortChange) & UPS_C_PORT_RESET) {
			break;
		}
		/* check for timeout */
		if (n > 1000) {
			n = 0;
			break;
		}
	}

	/* clear port reset first */
	err = usbd_req_clear_port_feature(
	    udev, mtx, port, UHF_C_PORT_RESET);
	if (err) {
		goto done;
	}
	/* check for timeout */
	if (n == 0) {
		err = USB_ERR_TIMEOUT;
		goto done;
	}
#if USB_DEBUG
	/* wait for the device to recover from reset */
	usb_pause_mtx(mtx, USB_MS_TO_TICKS(pr_recovery_delay));
#else
	/* wait for the device to recover from reset */
	usb_pause_mtx(mtx, USB_MS_TO_TICKS(USB_PORT_RESET_RECOVERY));
#endif

done:
	DPRINTFN(2, "port %d reset returning error=%s\n",
	    port, usbd_errstr(err));
	return (err);
}
Esempio n. 4
0
static void
usie_if_status_cb(void *arg, int pending)
{
	struct usie_softc *sc = arg;
	struct ifnet *ifp = sc->sc_ifp;
	struct usb_device_request req;
	struct usie_hip *hip;
	struct usie_lsi *lsi;
	uint16_t actlen;
	uint8_t ntries;
	uint8_t pad;

	mtx_lock(&sc->sc_mtx);

	req.bmRequestType = UT_READ_CLASS_INTERFACE;
	req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
	USETW(req.wValue, 0);
	USETW(req.wIndex, sc->sc_if_ifnum);
	USETW(req.wLength, sizeof(sc->sc_status_temp));

	for (ntries = 0; ntries != 10; ntries++) {
		int err;

		err = usbd_do_request_flags(sc->sc_udev,
		    &sc->sc_mtx, &req, sc->sc_status_temp, USB_SHORT_XFER_OK,
		    &actlen, USB_DEFAULT_TIMEOUT);

		if (err == 0)
			break;

		DPRINTF("Control request failed: %s %d/10\n",
		    usbd_errstr(err), ntries);

		usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(10));
	}

	if (ntries == 10) {
		mtx_unlock(&sc->sc_mtx);
		DPRINTF("Timeout\n");
		return;
	}

	hip = (struct usie_hip *)sc->sc_status_temp;

	pad = (hip->id & USIE_HIP_PAD) ? 1 : 0;

	DPRINTF("hip.id=%x hip.len=%d actlen=%u pad=%d\n",
	    hip->id, be16toh(hip->len), actlen, pad);

	switch (hip->id & USIE_HIP_MASK) {
	case USIE_HIP_SYNC2H:
		usie_if_cmd(sc, USIE_HIP_SYNC2M);
		break;
	case USIE_HIP_RESTR:
		usb_callout_stop(&sc->sc_if_sync_ch);
		break;
	case USIE_HIP_UMTS:
		lsi = (struct usie_lsi *)(
		    sc->sc_status_temp + sizeof(struct usie_hip) + pad);

		DPRINTF("lsi.proto=%x lsi.len=%d\n", lsi->proto,
		    be16toh(lsi->len));

		if (lsi->proto != USIE_LSI_UMTS)
			break;

		if (lsi->area == USIE_LSI_AREA_NO ||
		    lsi->area == USIE_LSI_AREA_NODATA) {
			device_printf(sc->sc_dev, "no service available\n");
			break;
		}
		if (lsi->state == USIE_LSI_STATE_IDLE) {
			DPRINTF("lsi.state=%x\n", lsi->state);
			break;
		}
		DPRINTF("ctx=%x\n", hip->param);
		sc->sc_txd.hip.param = hip->param;

		sc->sc_net.addr_len = lsi->pdp_addr_len;
		memcpy(&sc->sc_net.dns1_addr, &lsi->dns1_addr, 16);
		memcpy(&sc->sc_net.dns2_addr, &lsi->dns2_addr, 16);
		memcpy(sc->sc_net.pdp_addr, lsi->pdp_addr, 16);
		memcpy(sc->sc_net.gw_addr, lsi->gw_addr, 16);
		ifp->if_flags |= IFF_UP;
		ifp->if_drv_flags |= IFF_DRV_RUNNING;

		device_printf(sc->sc_dev, "IP Addr=%d.%d.%d.%d\n",
		    *lsi->pdp_addr, *(lsi->pdp_addr + 1),
		    *(lsi->pdp_addr + 2), *(lsi->pdp_addr + 3));
		device_printf(sc->sc_dev, "Gateway Addr=%d.%d.%d.%d\n",
		    *lsi->gw_addr, *(lsi->gw_addr + 1),
		    *(lsi->gw_addr + 2), *(lsi->gw_addr + 3));
		device_printf(sc->sc_dev, "Prim NS Addr=%d.%d.%d.%d\n",
		    *lsi->dns1_addr, *(lsi->dns1_addr + 1),
		    *(lsi->dns1_addr + 2), *(lsi->dns1_addr + 3));
		device_printf(sc->sc_dev, "Scnd NS Addr=%d.%d.%d.%d\n",
		    *lsi->dns2_addr, *(lsi->dns2_addr + 1),
		    *(lsi->dns2_addr + 2), *(lsi->dns2_addr + 3));

		usie_cns_req(sc, USIE_CNS_ID_RSSI, USIE_CNS_OB_RSSI);
		break;

	case USIE_HIP_RCGI:
		/* ignore, workaround for sloppy windows */
		break;
	default:
		DPRINTF("undefined msgid: %x\n", hip->id);
		break;
	}

	mtx_unlock(&sc->sc_mtx);
}
/*------------------------------------------------------------------------*
 *	usbd_do_request_flags and usbd_do_request
 *
 * Description of arguments passed to these functions:
 *
 * "udev" - this is the "usb_device" structure pointer on which the
 * request should be performed. It is possible to call this function
 * in both Host Side mode and Device Side mode.
 *
 * "mtx" - if this argument is non-NULL the mutex pointed to by it
 * will get dropped and picked up during the execution of this
 * function, hence this function sometimes needs to sleep. If this
 * argument is NULL it has no effect.
 *
 * "req" - this argument must always be non-NULL and points to an
 * 8-byte structure holding the USB request to be done. The USB
 * request structure has a bit telling the direction of the USB
 * request, if it is a read or a write.
 *
 * "data" - if the "wLength" part of the structure pointed to by "req"
 * is non-zero this argument must point to a valid kernel buffer which
 * can hold at least "wLength" bytes. If "wLength" is zero "data" can
 * be NULL.
 *
 * "flags" - here is a list of valid flags:
 *
 *  o USB_SHORT_XFER_OK: allows the data transfer to be shorter than
 *  specified
 *
 *  o USB_DELAY_STATUS_STAGE: allows the status stage to be performed
 *  at a later point in time. This is tunable by the "hw.usb.ss_delay"
 *  sysctl. This flag is mostly useful for debugging.
 *
 *  o USB_USER_DATA_PTR: treat the "data" pointer like a userland
 *  pointer.
 *
 * "actlen" - if non-NULL the actual transfer length will be stored in
 * the 16-bit unsigned integer pointed to by "actlen". This
 * information is mostly useful when the "USB_SHORT_XFER_OK" flag is
 * used.
 *
 * "timeout" - gives the timeout for the control transfer in
 * milliseconds. A "timeout" value less than 50 milliseconds is
 * treated like a 50 millisecond timeout. A "timeout" value greater
 * than 30 seconds is treated like a 30 second timeout. This USB stack
 * does not allow control requests without a timeout.
 *
 * NOTE: This function is thread safe. All calls to
 * "usbd_do_request_flags" will be serialised by the use of an
 * internal "sx_lock".
 *
 * Returns:
 *    0: Success
 * Else: Failure
 *------------------------------------------------------------------------*/
usb_error_t
usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
    struct usb_device_request *req, void *data, uint16_t flags,
    uint16_t *actlen, usb_timeout_t timeout)
{
	usb_handle_req_t *hr_func;
	struct usb_xfer *xfer;
	const void *desc;
	int err = 0;
	usb_ticks_t start_ticks;
	usb_ticks_t delta_ticks;
	usb_ticks_t max_ticks;
	uint16_t length;
	uint16_t temp;

	if (timeout < 50) {
		/* timeout is too small */
		timeout = 50;
	}
	if (timeout > 30000) {
		/* timeout is too big */
		timeout = 30000;
	}
	length = UGETW(req->wLength);

	DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x "
	    "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n",
	    udev, req->bmRequestType, req->bRequest,
	    req->wValue[1], req->wValue[0],
	    req->wIndex[1], req->wIndex[0],
	    req->wLength[1], req->wLength[0]);

	/* Check if the device is still alive */
	if (udev->state < USB_STATE_POWERED) {
		DPRINTF("usb device has gone\n");
		return (USB_ERR_NOT_CONFIGURED);
	}

	/*
	 * Set "actlen" to a known value in case the caller does not
	 * check the return value:
	 */
	if (actlen)
		*actlen = 0;

#if (USB_HAVE_USER_IO == 0)
	if (flags & USB_USER_DATA_PTR)
		return (USB_ERR_INVAL);
#endif
	if (mtx) {
		mtx_unlock(mtx);
		if (mtx != &Giant) {
			mtx_assert(mtx, MA_NOTOWNED);
		}
	}
	/*
	 * Grab the default sx-lock so that serialisation
	 * is achieved when multiple threads are involved:
	 */

	sx_xlock(udev->default_sx);

	hr_func = usbd_get_hr_func(udev);

	if (hr_func != NULL) {
		DPRINTF("Handle Request function is set\n");

		desc = NULL;
		temp = 0;

		if (!(req->bmRequestType & UT_READ)) {
			if (length != 0) {
				DPRINTFN(1, "The handle request function "
				    "does not support writing data!\n");
				err = USB_ERR_INVAL;
				goto done;
			}
		}

		/* The root HUB code needs the BUS lock locked */

		USB_BUS_LOCK(udev->bus);
		err = (hr_func) (udev, req, &desc, &temp);
		USB_BUS_UNLOCK(udev->bus);

		if (err)
			goto done;

		if (length > temp) {
			if (!(flags & USB_SHORT_XFER_OK)) {
				err = USB_ERR_SHORT_XFER;
				goto done;
			}
			length = temp;
		}
		if (actlen)
			*actlen = length;

		if (length > 0) {
#if USB_HAVE_USER_IO
			if (flags & USB_USER_DATA_PTR) {
				if (copyout(desc, data, length)) {
					err = USB_ERR_INVAL;
					goto done;
				}
			} else
#endif
				bcopy(desc, data, length);
		}
		goto done;		/* success */
	}

	/*
	 * Setup a new USB transfer or use the existing one, if any:
	 */
	usbd_default_transfer_setup(udev);

	xfer = udev->default_xfer[0];
	if (xfer == NULL) {
		/* most likely out of memory */
		err = USB_ERR_NOMEM;
		goto done;
	}
	USB_XFER_LOCK(xfer);

	if (flags & USB_DELAY_STATUS_STAGE)
		xfer->flags.manual_status = 1;
	else
		xfer->flags.manual_status = 0;

	if (flags & USB_SHORT_XFER_OK)
		xfer->flags.short_xfer_ok = 1;
	else
		xfer->flags.short_xfer_ok = 0;

	xfer->timeout = timeout;

	start_ticks = ticks;

	max_ticks = USB_MS_TO_TICKS(timeout);

	usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req));

	usbd_xfer_set_frame_len(xfer, 0, sizeof(*req));
	xfer->nframes = 2;

	while (1) {
		temp = length;
		if (temp > xfer->max_data_length) {
			temp = usbd_xfer_max_len(xfer);
		}
		usbd_xfer_set_frame_len(xfer, 1, temp);

		if (temp > 0) {
			if (!(req->bmRequestType & UT_READ)) {
#if USB_HAVE_USER_IO
				if (flags & USB_USER_DATA_PTR) {
					USB_XFER_UNLOCK(xfer);
					err = usbd_copy_in_user(xfer->frbuffers + 1,
					    0, data, temp);
					USB_XFER_LOCK(xfer);
					if (err) {
						err = USB_ERR_INVAL;
						break;
					}
				} else
#endif
					usbd_copy_in(xfer->frbuffers + 1,
					    0, data, temp);
			}
			xfer->nframes = 2;
		} else {
			if (xfer->frlengths[0] == 0) {
				if (xfer->flags.manual_status) {
#if USB_DEBUG
					int temp;

					temp = usb_ss_delay;
					if (temp > 5000) {
						temp = 5000;
					}
					if (temp > 0) {
						usb_pause_mtx(
						    xfer->xroot->xfer_mtx,
						    USB_MS_TO_TICKS(temp));
					}
#endif
					xfer->flags.manual_status = 0;
				} else {
					break;
				}
			}
			xfer->nframes = 1;
		}

		usbd_transfer_start(xfer);

		while (usbd_transfer_pending(xfer)) {
			cv_wait(udev->default_cv,
			    xfer->xroot->xfer_mtx);
		}

		err = xfer->error;

		if (err) {
			break;
		}
		/* subtract length of SETUP packet, if any */

		if (xfer->aframes > 0) {
			xfer->actlen -= xfer->frlengths[0];
		} else {
			xfer->actlen = 0;
		}

		/* check for short packet */

		if (temp > xfer->actlen) {
			temp = xfer->actlen;
			length = temp;
		}
		if (temp > 0) {
			if (req->bmRequestType & UT_READ) {
#if USB_HAVE_USER_IO
				if (flags & USB_USER_DATA_PTR) {
					USB_XFER_UNLOCK(xfer);
					err = usbd_copy_out_user(xfer->frbuffers + 1,
					    0, data, temp);
					USB_XFER_LOCK(xfer);
					if (err) {
						err = USB_ERR_INVAL;
						break;
					}
				} else
#endif
					usbd_copy_out(xfer->frbuffers + 1,
					    0, data, temp);
			}
		}
		/*
		 * Clear "frlengths[0]" so that we don't send the setup
		 * packet again:
		 */
		usbd_xfer_set_frame_len(xfer, 0, 0);

		/* update length and data pointer */
		length -= temp;
		data = USB_ADD_BYTES(data, temp);

		if (actlen) {
			(*actlen) += temp;
		}
		/* check for timeout */

		delta_ticks = ticks - start_ticks;
		if (delta_ticks > max_ticks) {
			if (!err) {
				err = USB_ERR_TIMEOUT;
			}
		}
		if (err) {
			break;
		}
	}

	if (err) {
		/*
		 * Make sure that the control endpoint is no longer
		 * blocked in case of a non-transfer related error:
		 */
		usbd_transfer_stop(xfer);
	}
	USB_XFER_UNLOCK(xfer);

done:
	sx_xunlock(udev->default_sx);

	if (mtx) {
		mtx_lock(mtx);
	}
	return ((usb_error_t)err);
}