示例#1
0
文件: ugen.c 项目: SylvestreG/bitrig
int
ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd,
	      caddr_t addr, int flag, struct proc *p)
{
	struct ugen_endpoint *sce;
	int err;
	struct usbd_interface *iface;
	struct usb_config_desc *cd;
	usb_config_descriptor_t *cdesc;
	struct usb_interface_desc *id;
	usb_interface_descriptor_t *idesc;
	struct usb_endpoint_desc *ed;
	usb_endpoint_descriptor_t *edesc;
	struct usb_alt_interface *ai;
	struct usb_string_desc *si;
	u_int8_t conf, alt;

	DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd));
	if (usbd_is_dying(sc->sc_udev))
		return (EIO);

	switch (cmd) {
	case FIONBIO:
		/* All handled in the upper FS layer. */
		return (0);
	case USB_SET_SHORT_XFER:
		if (endpt == USB_CONTROL_ENDPOINT)
			return (EINVAL);
		/* This flag only affects read */
		sce = &sc->sc_endpoints[endpt][IN];
		if (sce == NULL || sce->pipeh == NULL)
			return (EINVAL);
		if (*(int *)addr)
			sce->state |= UGEN_SHORT_OK;
		else
			sce->state &= ~UGEN_SHORT_OK;
		return (0);
	case USB_SET_TIMEOUT:
		sce = &sc->sc_endpoints[endpt][IN];
		if (sce == NULL)
			return (EINVAL);
		sce->timeout = *(int *)addr;
		sce = &sc->sc_endpoints[endpt][OUT];
		if (sce == NULL)
			return (EINVAL);
		sce->timeout = *(int *)addr;
		return (0);
	default:
		break;
	}

	if (endpt != USB_CONTROL_ENDPOINT)
		return (EINVAL);

	switch (cmd) {
#ifdef UGEN_DEBUG
	case USB_SETDEBUG:
		ugendebug = *(int *)addr;
		break;
#endif
	case USB_GET_CONFIG:
		err = usbd_get_config(sc->sc_udev, &conf);
		if (err)
			return (EIO);
		*(int *)addr = conf;
		break;
	case USB_SET_CONFIG:
		if (!(flag & FWRITE))
			return (EPERM);
		err = ugen_set_config(sc, *(int *)addr);
		switch (err) {
		case USBD_NORMAL_COMPLETION:
			break;
		case USBD_IN_USE:
			return (EBUSY);
		default:
			return (EIO);
		}
		break;
	case USB_GET_ALTINTERFACE:
		ai = (struct usb_alt_interface *)addr;
		err = usbd_device2interface_handle(sc->sc_udev,
			  ai->uai_interface_index, &iface);
		if (err)
			return (EINVAL);
		idesc = usbd_get_interface_descriptor(iface);
		if (idesc == NULL)
			return (EIO);
		ai->uai_alt_no = idesc->bAlternateSetting;
		break;
	case USB_SET_ALTINTERFACE:
		if (!(flag & FWRITE))
			return (EPERM);
		ai = (struct usb_alt_interface *)addr;
		err = usbd_device2interface_handle(sc->sc_udev,
			  ai->uai_interface_index, &iface);
		if (err)
			return (EINVAL);
		err = ugen_set_interface(sc, ai->uai_interface_index,
		    ai->uai_alt_no);
		if (err)
			return (EINVAL);
		break;
	case USB_GET_NO_ALT:
		ai = (struct usb_alt_interface *)addr;
		cdesc = usbd_get_cdesc(sc->sc_udev, ai->uai_config_index, 0);
		if (cdesc == NULL)
			return (EINVAL);
		idesc = usbd_find_idesc(cdesc, ai->uai_interface_index, 0);
		if (idesc == NULL) {
			free(cdesc, M_TEMP, 0);
			return (EINVAL);
		}
		ai->uai_alt_no = usbd_get_no_alts(cdesc,
		    idesc->bInterfaceNumber);
		free(cdesc, M_TEMP, 0);
		break;
	case USB_GET_DEVICE_DESC:
		*(usb_device_descriptor_t *)addr =
			*usbd_get_device_descriptor(sc->sc_udev);
		break;
	case USB_GET_CONFIG_DESC:
		cd = (struct usb_config_desc *)addr;
		cdesc = usbd_get_cdesc(sc->sc_udev, cd->ucd_config_index, 0);
		if (cdesc == NULL)
			return (EINVAL);
		cd->ucd_desc = *cdesc;
		free(cdesc, M_TEMP, 0);
		break;
	case USB_GET_INTERFACE_DESC:
		id = (struct usb_interface_desc *)addr;
		cdesc = usbd_get_cdesc(sc->sc_udev, id->uid_config_index, 0);
		if (cdesc == NULL)
			return (EINVAL);
		if (id->uid_config_index == USB_CURRENT_CONFIG_INDEX &&
		    id->uid_alt_index == USB_CURRENT_ALT_INDEX)
			alt = ugen_get_alt_index(sc, id->uid_interface_index);
		else
			alt = id->uid_alt_index;
		idesc = usbd_find_idesc(cdesc, id->uid_interface_index, alt);
		if (idesc == NULL) {
			free(cdesc, M_TEMP, 0);
			return (EINVAL);
		}
		id->uid_desc = *idesc;
		free(cdesc, M_TEMP, 0);
		break;
	case USB_GET_ENDPOINT_DESC:
		ed = (struct usb_endpoint_desc *)addr;
		cdesc = usbd_get_cdesc(sc->sc_udev, ed->ued_config_index, 0);
		if (cdesc == NULL)
			return (EINVAL);
		if (ed->ued_config_index == USB_CURRENT_CONFIG_INDEX &&
		    ed->ued_alt_index == USB_CURRENT_ALT_INDEX)
			alt = ugen_get_alt_index(sc, ed->ued_interface_index);
		else
			alt = ed->ued_alt_index;
		edesc = usbd_find_edesc(cdesc, ed->ued_interface_index,
					alt, ed->ued_endpoint_index);
		if (edesc == NULL) {
			free(cdesc, M_TEMP, 0);
			return (EINVAL);
		}
		ed->ued_desc = *edesc;
		free(cdesc, M_TEMP, 0);
		break;
	case USB_GET_FULL_DESC:
	{
		int len;
		struct iovec iov;
		struct uio uio;
		struct usb_full_desc *fd = (struct usb_full_desc *)addr;
		int error;

		cdesc = usbd_get_cdesc(sc->sc_udev, fd->ufd_config_index, &len);
		if (cdesc == NULL)
			return (EINVAL);
		if (len > fd->ufd_size)
			len = fd->ufd_size;
		iov.iov_base = (caddr_t)fd->ufd_data;
		iov.iov_len = len;
		uio.uio_iov = &iov;
		uio.uio_iovcnt = 1;
		uio.uio_resid = len;
		uio.uio_offset = 0;
		uio.uio_segflg = UIO_USERSPACE;
		uio.uio_rw = UIO_READ;
		uio.uio_procp = p;
		error = uiomove((void *)cdesc, len, &uio);
		free(cdesc, M_TEMP, 0);
		return (error);
	}
	case USB_GET_STRING_DESC:
	{
		int len;
		si = (struct usb_string_desc *)addr;
		err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index,
			si->usd_language_id, &si->usd_desc, &len);
		if (err)
			return (EINVAL);
		break;
	}
	case USB_DO_REQUEST:
	{
		struct usb_ctl_request *ur = (void *)addr;
		int len = UGETW(ur->ucr_request.wLength);
		struct iovec iov;
		struct uio uio;
		void *ptr = 0;
		int error = 0;

		if (!(flag & FWRITE))
			return (EPERM);
		/* Avoid requests that would damage the bus integrity. */
		if ((ur->ucr_request.bmRequestType == UT_WRITE_DEVICE &&
		     ur->ucr_request.bRequest == UR_SET_ADDRESS) ||
		    (ur->ucr_request.bmRequestType == UT_WRITE_DEVICE &&
		     ur->ucr_request.bRequest == UR_SET_CONFIG) ||
		    (ur->ucr_request.bmRequestType == UT_WRITE_INTERFACE &&
		     ur->ucr_request.bRequest == UR_SET_INTERFACE))
			return (EINVAL);

		if (len < 0 || len > 32767)
			return (EINVAL);
		if (len != 0) {
			iov.iov_base = (caddr_t)ur->ucr_data;
			iov.iov_len = len;
			uio.uio_iov = &iov;
			uio.uio_iovcnt = 1;
			uio.uio_resid = len;
			uio.uio_offset = 0;
			uio.uio_segflg = UIO_USERSPACE;
			uio.uio_rw =
				ur->ucr_request.bmRequestType & UT_READ ?
				UIO_READ : UIO_WRITE;
			uio.uio_procp = p;
			ptr = malloc(len, M_TEMP, M_WAITOK);
			if (uio.uio_rw == UIO_WRITE) {
				error = uiomove(ptr, len, &uio);
				if (error)
					goto ret;
			}
		}
		sce = &sc->sc_endpoints[endpt][IN];
		err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request,
			  ptr, ur->ucr_flags, &ur->ucr_actlen, sce->timeout);
		if (err) {
			error = EIO;
			goto ret;
		}
		/* Only if USBD_SHORT_XFER_OK is set. */
		if (len > ur->ucr_actlen)
			len = ur->ucr_actlen;
		if (len != 0) {
			if (uio.uio_rw == UIO_READ) {
				error = uiomove(ptr, len, &uio);
				if (error)
					goto ret;
			}
		}
	ret:
		if (ptr)
			free(ptr, M_TEMP, 0);
		return (error);
	}
	case USB_GET_DEVICEINFO:
		usbd_fill_deviceinfo(sc->sc_udev,
				     (struct usb_device_info *)addr, 1);
		break;
	default:
		return (EINVAL);
	}
	return (0);
}
示例#2
0
int
uhub_explore(struct usbd_device *dev)
{
	struct uhub_softc *sc = dev->hub->hubsoftc;
	struct usbd_port *up;
	int status, change;
	int port;

	if (usbd_is_dying(sc->sc_hub))
		return (EIO);

	if (!sc->sc_running)
		return (ENXIO);

	/* Ignore hubs that are too deep. */
	if (sc->sc_hub->depth > USB_HUB_MAX_DEPTH)
		return (EOPNOTSUPP);

	for (port = 1; port <= sc->sc_hub->hub->nports; port++) {
		up = &sc->sc_hub->hub->ports[port-1];

		change = 0;
		status = 0;

		if ((sc->sc_status & (1 << port)) || up->reattach) {
			sc->sc_status &= ~(1 << port);

			if (usbd_get_port_status(dev, port, &up->status))
				continue;

			status = UGETW(up->status.wPortStatus);
			change = UGETW(up->status.wPortChange);
			DPRINTF("%s: port %d status=0x%04x change=0x%04x\n",
			    sc->sc_dev.dv_xname, port, status, change);
		}

		if (up->reattach) {
			change |= UPS_C_CONNECT_STATUS;
			up->reattach = 0;
		}

		if (change & UPS_C_PORT_ENABLED) {
			usbd_clear_port_feature(sc->sc_hub, port,
			    UHF_C_PORT_ENABLE);
			if (change & UPS_C_CONNECT_STATUS) {
				/* Ignore the port error if the device
				   vanished. */
			} else if (status & UPS_PORT_ENABLED) {
				printf("%s: illegal enable change, port %d\n",
				       sc->sc_dev.dv_xname, port);
			} else {
				/* Port error condition. */
				if (up->restartcnt) /* no message first time */
					printf("%s: port error, restarting "
					       "port %d\n",
					       sc->sc_dev.dv_xname, port);

				if (up->restartcnt++ < USBD_RESTART_MAX)
					change |= UPS_C_CONNECT_STATUS;
				else
					printf("%s: port error, giving up "
					       "port %d\n",
					       sc->sc_dev.dv_xname, port);
			}
		}

		if (change & UPS_C_CONNECT_STATUS) {
			if (uhub_port_connect(sc, port, status, change))
				continue;

			/* The port set up succeeded, reset error count. */
			up->restartcnt = 0;
		}

		if (change & UPS_C_PORT_LINK_STATE) {
			usbd_clear_port_feature(sc->sc_hub, port,
			    UHF_C_PORT_LINK_STATE);
		}

		/* Recursive explore. */
		if (up->device != NULL && up->device->hub != NULL)
			up->device->hub->explore(up->device);
	}

	return (0);
}
示例#3
0
文件: if_url.c 项目: MarginC/kame
Static void
url_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
{
	struct url_chain *c = priv;
	struct url_softc *sc = c->url_sc;
	struct ifnet *ifp = GET_IFP(sc);
	struct mbuf *m;
	u_int32_t total_len;
	url_rxhdr_t rxhdr;
	int s;

	DPRINTF(("%s: %s: enter\n", USBDEVNAME(sc->sc_dev),__func__));

	if (sc->sc_dying)
		return;

	if (status != USBD_NORMAL_COMPLETION) {
		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
			return;
		sc->sc_rx_errs++;
		if (usbd_ratecheck(&sc->sc_rx_notice)) {
			printf("%s: %u usb errors on rx: %s\n",
			       USBDEVNAME(sc->sc_dev), sc->sc_rx_errs,
			       usbd_errstr(status));
			sc->sc_rx_errs = 0;
		}
		if (status == USBD_STALLED) {
			sc->sc_refcnt++;
			usbd_clear_endpoint_stall(sc->sc_pipe_rx);
			if (--sc->sc_refcnt < 0)
				usb_detach_wakeup(USBDEV(sc->sc_dev));
		}
		goto done;
	}

	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);

	memcpy(mtod(c->url_mbuf, char *), c->url_buf, total_len);

	if (total_len <= ETHER_CRC_LEN) {
		ifp->if_ierrors++;
		goto done;
	}

	memcpy(&rxhdr, c->url_buf + total_len - ETHER_CRC_LEN, sizeof(rxhdr));

	DPRINTF(("%s: RX Status: %dbytes%s%s%s%s packets\n",
		 USBDEVNAME(sc->sc_dev),
		 UGETW(rxhdr) & URL_RXHDR_BYTEC_MASK,
		 UGETW(rxhdr) & URL_RXHDR_VALID_MASK ? ", Valid" : "",
		 UGETW(rxhdr) & URL_RXHDR_RUNTPKT_MASK ? ", Runt" : "",
		 UGETW(rxhdr) & URL_RXHDR_PHYPKT_MASK ? ", Physical match" : "",
		 UGETW(rxhdr) & URL_RXHDR_MCASTPKT_MASK ? ", Multicast" : ""));

	if ((UGETW(rxhdr) & URL_RXHDR_VALID_MASK) == 0) {
		ifp->if_ierrors++;
		goto done;
	}

	ifp->if_ipackets++;
	total_len -= ETHER_CRC_LEN;

	m = c->url_mbuf;
	m->m_pkthdr.len = m->m_len = total_len;
	m->m_pkthdr.rcvif = ifp;

	s = splnet();

	if (url_newbuf(sc, c, NULL) == ENOBUFS) {
		ifp->if_ierrors++;
		goto done1;
	}

#if NBPFILTER > 0
	if (ifp->if_bpf)
		BPF_MTAP(ifp, m);
#endif

	DPRINTF(("%s: %s: deliver %d\n", USBDEVNAME(sc->sc_dev),
		 __func__, m->m_len));
	IF_INPUT(ifp, m);

 done1:
	splx(s);

 done:
	/* Setup new transfer */
	usbd_setup_xfer(xfer, sc->sc_pipe_rx, c, c->url_buf, URL_BUFSZ,
			USBD_SHORT_XFER_OK | USBD_NO_COPY,
			USBD_NO_TIMEOUT, url_rxeof);
	sc->sc_refcnt++;
	usbd_transfer(xfer);
	if (--sc->sc_refcnt < 0)
		usb_detach_wakeup(USBDEV(sc->sc_dev));

	DPRINTF(("%s: %s: start rx\n", USBDEVNAME(sc->sc_dev), __func__));
}
示例#4
0
void 
uftdi_attach(device_t parent, device_t self, void *aux)
{
	struct uftdi_softc *sc = device_private(self);
	struct usb_attach_arg *uaa = aux;
	usbd_device_handle dev = uaa->device;
	usbd_interface_handle iface;
	usb_device_descriptor_t *ddesc;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	char *devinfop;
	const char *devname = device_xname(self);
	int i,idx;
	usbd_status err;
	struct ucom_attach_args uca;

	DPRINTFN(10,("\nuftdi_attach: sc=%p\n", sc));

	aprint_naive("\n");
	aprint_normal("\n");

	devinfop = usbd_devinfo_alloc(dev, 0);
	aprint_normal_dev(self, "%s\n", devinfop);
	usbd_devinfo_free(devinfop);

	/* Move the device into the configured state. */
	err = usbd_set_config_index(dev, UFTDI_CONFIG_INDEX, 1);
	if (err) {
		aprint_error("\n%s: failed to set configuration, err=%s\n",
		       devname, usbd_errstr(err));
		goto bad;
	}

	sc->sc_dev = self;
	sc->sc_udev = dev;
	sc->sc_numports = 1;
	sc->sc_type = UFTDI_TYPE_8U232AM; /* most devices are post-8U232AM */
	sc->sc_hdrlen = 0;
	if (uaa->vendor == USB_VENDOR_FTDI
	    && uaa->product == USB_PRODUCT_FTDI_SERIAL_8U100AX) {
		sc->sc_type = UFTDI_TYPE_SIO;
		sc->sc_hdrlen = 1;
	}

	ddesc = usbd_get_device_descriptor(dev);
	sc->sc_chiptype = UGETW(ddesc->bcdDevice);
	switch (sc->sc_chiptype) {
	case 0x500: /* 2232D */
	case 0x700: /* 2232H */
		sc->sc_numports = 2;
		break;
	case 0x800: /* 4232H */
		sc->sc_numports = 4;
		break;
	case 0x200: /* 232/245AM */
	case 0x400: /* 232/245BL */
	case 0x600: /* 232/245R */
	default:
		break;
	}

	for (idx = UFTDI_IFACE_INDEX; idx < sc->sc_numports; idx++) {
		err = usbd_device2interface_handle(dev, idx, &iface);
		if (err) {
			aprint_error(
			    "\n%s: failed to get interface idx=%d, err=%s\n",
			    devname, idx, usbd_errstr(err));
			goto bad;
		}

		id = usbd_get_interface_descriptor(iface);

		sc->sc_iface[idx] = iface;

		uca.bulkin = uca.bulkout = -1;
		uca.ibufsize = uca.obufsize = 0;
		for (i = 0; i < id->bNumEndpoints; i++) {
			int addr, dir, attr;
			ed = usbd_interface2endpoint_descriptor(iface, i);
			if (ed == NULL) {
				aprint_error_dev(self,
				    "could not read endpoint descriptor: %s\n",
				    usbd_errstr(err));
				goto bad;
			}

			addr = ed->bEndpointAddress;
			dir = UE_GET_DIR(ed->bEndpointAddress);
			attr = ed->bmAttributes & UE_XFERTYPE;
			if (dir == UE_DIR_IN && attr == UE_BULK) {
				uca.bulkin = addr;
				uca.ibufsize = UGETW(ed->wMaxPacketSize);
				if (uca.ibufsize >= UFTDI_MAX_IBUFSIZE)
					uca.ibufsize = UFTDI_MAX_IBUFSIZE;
			} else if (dir == UE_DIR_OUT && attr == UE_BULK) {
				uca.bulkout = addr;
				uca.obufsize = UGETW(ed->wMaxPacketSize)
				    - sc->sc_hdrlen;
				if (uca.obufsize >= UFTDI_MAX_OBUFSIZE)
					uca.obufsize = UFTDI_MAX_OBUFSIZE;
				/* Limit length if we have a 6-bit header.  */
				if ((sc->sc_hdrlen > 0) &&
				    (uca.obufsize > UFTDIOBUFSIZE))
					uca.obufsize = UFTDIOBUFSIZE;
			} else {
				aprint_error_dev(self,
				    "unexpected endpoint\n");
				goto bad;
			}
		}
		if (uca.bulkin == -1) {
			aprint_error_dev(self,
			    "Could not find data bulk in\n");
			goto bad;
		}
		if (uca.bulkout == -1) {
			aprint_error_dev(self,
			    "Could not find data bulk out\n");
			goto bad;
		}

		uca.portno = FTDI_PIT_SIOA + idx;
		/* bulkin, bulkout set above */
		if (uca.ibufsize == 0)
			uca.ibufsize = UFTDIIBUFSIZE;
		uca.ibufsizepad = uca.ibufsize;
		if (uca.obufsize == 0)
			uca.obufsize = UFTDIOBUFSIZE - sc->sc_hdrlen;
		uca.opkthdrlen = sc->sc_hdrlen;
		uca.device = dev;
		uca.iface = iface;
		uca.methods = &uftdi_methods;
		uca.arg = sc;
		uca.info = NULL;

		DPRINTF(("uftdi: in=0x%x out=0x%x isize=0x%x osize=0x%x\n",
			uca.bulkin, uca.bulkout,
			uca.ibufsize, uca.obufsize));
		sc->sc_subdev[idx] = config_found_sm_loc(self, "ucombus", NULL,
		    &uca, ucomprint, ucomsubmatch);
	}

	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
			   sc->sc_dev);

	return;

bad:
	DPRINTF(("uftdi_attach: ATTACH ERROR\n"));
	sc->sc_dying = 1;
	return;
}
示例#5
0
static int
ugensa_attach(device_t self)
{
	struct ugensa_softc *sc = device_get_softc(self);
	struct usb_attach_arg *uaa = device_get_ivars(self);
	struct ucom_softc *ucom;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	int i;

	ucom = &sc->sc_ucom;
	bzero(sc, sizeof (struct ugensa_softc));

	ucom->sc_dev = self;
	ucom->sc_udev = uaa->device;
	ucom->sc_iface = uaa->iface;

	id = usbd_get_interface_descriptor(ucom->sc_iface);

	sc->sc_iface_no = id->bInterfaceNumber;
	ucom->sc_bulkin_no = ucom->sc_bulkout_no = -1;
	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(ucom->sc_iface, i);
		if (ed == NULL) {
			device_printf(ucom->sc_dev, "no endpoint descriptor "
				      "found for %d\n", i);
			goto error;
		}

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
			sc->sc_intr_number = ed->bEndpointAddress;
			sc->sc_isize = UGETW(ed->wMaxPacketSize);
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
			ucom->sc_bulkin_no = ed->bEndpointAddress;
		else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
			ucom->sc_bulkout_no = ed->bEndpointAddress;
	}
	if (ucom->sc_bulkin_no == -1 || ucom->sc_bulkout_no == -1) {
		device_printf(ucom->sc_dev, "missing endpoint\n");
		goto error;
	}

	sc->sc_dtr = sc->sc_rts = -1;

	ucom->sc_parent = sc;
	ucom->sc_portno = UCOM_UNK_PORTNO;
	ucom->sc_ibufsize = UGENSABUFSZ;
	ucom->sc_obufsize = UGENSABUFSZ;
	ucom->sc_ibufsizepad = UGENSABUFSZ;
	ucom->sc_opkthdrlen = 0;
	ucom->sc_callback = &ugensa_callback;

	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, ucom->sc_udev,
			   ucom->sc_dev);

	DPRINTF(("%s: in = 0x%x, out = 0x%x\n",
		 device_get_nameunit(ucom->sc_dev), ucom->sc_bulkin_no,
		 ucom->sc_bulkout_no));

	ucom_attach(&sc->sc_ucom);

	return 0;

error:
	ucom->sc_dying = 1;
	return ENXIO;
}
示例#6
0
/*------------------------------------------------------------------------*
 *	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);
}
示例#7
0
/*------------------------------------------------------------------------*
 *	usb_hw_ep_get_needs
 *
 * This function will figure out the type and number of endpoints
 * which are needed for an USB configuration.
 *
 * Return values:
 *    0: Success.
 * Else: Failure.
 *------------------------------------------------------------------------*/
static uint8_t
usb_hw_ep_get_needs(struct usb_hw_ep_scratch *ues,
    uint8_t ep_type, uint8_t is_complete)
{
	const struct usb_hw_ep_profile *pf;
	struct usb_hw_ep_scratch_sub *ep_iface;
	struct usb_hw_ep_scratch_sub *ep_curr;
	struct usb_hw_ep_scratch_sub *ep_max;
	struct usb_hw_ep_scratch_sub *ep_end;
	struct usb_descriptor *desc;
	struct usb_interface_descriptor *id;
	struct usb_endpoint_descriptor *ed;
	enum usb_dev_speed speed;
	uint16_t wMaxPacketSize;
	uint16_t temp;
	uint8_t ep_no;

	ep_iface = ues->ep_max;
	ep_curr = ues->ep_max;
	ep_end = ues->ep + USB_EP_MAX;
	ep_max = ues->ep_max;
	desc = NULL;
	speed = usbd_get_speed(ues->udev);

repeat:

	while ((desc = usb_desc_foreach(ues->cd, desc))) {

		if ((desc->bDescriptorType == UDESC_INTERFACE) &&
		    (desc->bLength >= sizeof(*id))) {

			id = (void *)desc;

			if (id->bAlternateSetting == 0) {
				/* going forward */
				ep_iface = ep_max;
			} else {
				/* reset */
				ep_curr = ep_iface;
			}
		}
		if ((desc->bDescriptorType == UDESC_ENDPOINT) &&
		    (desc->bLength >= sizeof(*ed))) {

			ed = (void *)desc;

			goto handle_endpoint_desc;
		}
	}
	ues->ep_max = ep_max;
	return (0);

handle_endpoint_desc:
	temp = (ed->bmAttributes & UE_XFERTYPE);

	if (temp == ep_type) {

		if (ep_curr == ep_end) {
			/* too many endpoints */
			return (1);	/* failure */
		}
		wMaxPacketSize = UGETW(ed->wMaxPacketSize);
		if ((wMaxPacketSize & 0xF800) &&
		    (speed == USB_SPEED_HIGH)) {
			/* handle packet multiplier */
			temp = (wMaxPacketSize >> 11) & 3;
			wMaxPacketSize &= 0x7FF;
			if (temp == 1) {
				wMaxPacketSize *= 2;
			} else {
				wMaxPacketSize *= 3;
			}
		}
		/*
		 * Check if we have a fixed endpoint number, else the
		 * endpoint number is allocated dynamically:
		 */
		ep_no = (ed->bEndpointAddress & UE_ADDR);
		if (ep_no != 0) {

			/* get HW endpoint profile */
			(ues->methods->get_hw_ep_profile)
			    (ues->udev, &pf, ep_no);
			if (pf == NULL) {
				/* HW profile does not exist - failure */
				DPRINTFN(0, "Endpoint profile %u "
				    "does not exist\n", ep_no);
				return (1);
			}
			/* reserve fixed endpoint number */
			if (ep_type == UE_CONTROL) {
				ues->bmInAlloc[ep_no / 8] |=
				    (1 << (ep_no % 8));
				ues->bmOutAlloc[ep_no / 8] |=
				    (1 << (ep_no % 8));
				if ((pf->max_in_frame_size < wMaxPacketSize) ||
				    (pf->max_out_frame_size < wMaxPacketSize)) {
					DPRINTFN(0, "Endpoint profile %u "
					    "has too small buffer\n", ep_no);
					return (1);
				}
			} else if (ed->bEndpointAddress & UE_DIR_IN) {
				ues->bmInAlloc[ep_no / 8] |=
				    (1 << (ep_no % 8));
				if (pf->max_in_frame_size < wMaxPacketSize) {
					DPRINTFN(0, "Endpoint profile %u "
					    "has too small buffer\n", ep_no);
					return (1);
				}
			} else {
				ues->bmOutAlloc[ep_no / 8] |=
				    (1 << (ep_no % 8));
				if (pf->max_out_frame_size < wMaxPacketSize) {
					DPRINTFN(0, "Endpoint profile %u "
					    "has too small buffer\n", ep_no);
					return (1);
				}
			}
		} else if (is_complete) {

			/* check if we have enough buffer space */
			if (wMaxPacketSize >
			    ep_curr->max_frame_size) {
				return (1);	/* failure */
			}
			if (ed->bEndpointAddress & UE_DIR_IN) {
				ed->bEndpointAddress =
				    ep_curr->hw_endpoint_in;
			} else {
				ed->bEndpointAddress =
				    ep_curr->hw_endpoint_out;
			}

		} else {

			/* compute the maximum frame size */
			if (ep_curr->max_frame_size < wMaxPacketSize) {
				ep_curr->max_frame_size = wMaxPacketSize;
			}
			if (temp == UE_CONTROL) {
				ep_curr->needs_in = 1;
				ep_curr->needs_out = 1;
			} else {
				if (ed->bEndpointAddress & UE_DIR_IN) {
					ep_curr->needs_in = 1;
				} else {
					ep_curr->needs_out = 1;
				}
			}
			ep_curr->needs_ep_type = ep_type;
		}

		ep_curr++;
		if (ep_max < ep_curr) {
			ep_max = ep_curr;
		}
	}
示例#8
0
文件: usb_subr.c 项目: ryo/netbsd-src
usbd_status
usbd_fill_iface_data(struct usbd_device *dev, int ifaceidx, int altidx)
{
	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
	struct usbd_interface *ifc = &dev->ud_ifaces[ifaceidx];
	usb_interface_descriptor_t *idesc;
	char *p, *end;
	int endpt, nendpt;

	DPRINTFN(4, "ifaceidx=%d altidx=%d", ifaceidx, altidx, 0, 0);
	idesc = usbd_find_idesc(dev->ud_cdesc, ifaceidx, altidx);
	if (idesc == NULL)
		return USBD_INVAL;
	ifc->ui_dev = dev;
	ifc->ui_idesc = idesc;
	ifc->ui_index = ifaceidx;
	ifc->ui_altindex = altidx;
	nendpt = ifc->ui_idesc->bNumEndpoints;
	DPRINTFN(4, "found idesc nendpt=%d", nendpt, 0, 0, 0);
	if (nendpt != 0) {
		ifc->ui_endpoints = kmem_alloc(nendpt * sizeof(struct usbd_endpoint),
				KM_SLEEP);
		if (ifc->ui_endpoints == NULL)
			return USBD_NOMEM;
	} else
		ifc->ui_endpoints = NULL;
	ifc->ui_priv = NULL;
	p = (char *)ifc->ui_idesc + ifc->ui_idesc->bLength;
	end = (char *)dev->ud_cdesc + UGETW(dev->ud_cdesc->wTotalLength);
#define ed ((usb_endpoint_descriptor_t *)p)
	for (endpt = 0; endpt < nendpt; endpt++) {
		DPRINTFN(10, "endpt=%d", endpt, 0, 0, 0);
		for (; p < end; p += ed->bLength) {
			DPRINTFN(10, "p=%p end=%p len=%d type=%d",
			    p, end, ed->bLength, ed->bDescriptorType);
			if (p + ed->bLength <= end && ed->bLength != 0 &&
			    ed->bDescriptorType == UDESC_ENDPOINT)
				goto found;
			if (ed->bLength == 0 ||
			    ed->bDescriptorType == UDESC_INTERFACE)
				break;
		}
		/* passed end, or bad desc */
		printf("usbd_fill_iface_data: bad descriptor(s): %s\n",
		       ed->bLength == 0 ? "0 length" :
		       ed->bDescriptorType == UDESC_INTERFACE ? "iface desc":
		       "out of data");
		goto bad;
	found:
		ifc->ui_endpoints[endpt].ue_edesc = ed;
		if (dev->ud_speed == USB_SPEED_HIGH) {
			u_int mps;
			/* Control and bulk endpoints have max packet limits. */
			switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
			case UE_CONTROL:
				mps = USB_2_MAX_CTRL_PACKET;
				goto check;
			case UE_BULK:
				mps = USB_2_MAX_BULK_PACKET;
			check:
				if (UGETW(ed->wMaxPacketSize) != mps) {
					USETW(ed->wMaxPacketSize, mps);
#ifdef DIAGNOSTIC
					printf("usbd_fill_iface_data: bad max "
					       "packet size\n");
#endif
				}
				break;
			default:
				break;
			}
		}
		ifc->ui_endpoints[endpt].ue_refcnt = 0;
		ifc->ui_endpoints[endpt].ue_toggle = 0;
		p += ed->bLength;
	}
#undef ed
	LIST_INIT(&ifc->ui_pipes);
	return USBD_NORMAL_COMPLETION;

 bad:
	if (ifc->ui_endpoints != NULL) {
		kmem_free(ifc->ui_endpoints, nendpt * sizeof(struct usbd_endpoint));
		ifc->ui_endpoints = NULL;
	}
	return USBD_INVAL;
}
示例#9
0
文件: usb_subr.c 项目: ryo/netbsd-src
usbd_status
usbd_set_config_index(struct usbd_device *dev, int index, int msg)
{
	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
	usb_config_descriptor_t cd, *cdp;
	usb_bos_descriptor_t *bdp = NULL;
	usbd_status err;
	int i, ifcidx, nifc, len, selfpowered, power;

	DPRINTFN(5, "dev=%p index=%d", dev, index, 0, 0);

	if (index >= dev->ud_ddesc.bNumConfigurations &&
	    index != USB_UNCONFIG_INDEX) {
		/* panic? */
		printf("usbd_set_config_index: illegal index\n");
		return USBD_INVAL;
	}

	/* XXX check that all interfaces are idle */
	if (dev->ud_config != USB_UNCONFIG_NO) {
		DPRINTF("free old config", 0, 0, 0, 0);
		/* Free all configuration data structures. */
		nifc = dev->ud_cdesc->bNumInterface;
		for (ifcidx = 0; ifcidx < nifc; ifcidx++)
			usbd_free_iface_data(dev, ifcidx);
		kmem_free(dev->ud_ifaces, nifc * sizeof(struct usbd_interface));
		kmem_free(dev->ud_cdesc, UGETW(dev->ud_cdesc->wTotalLength));
		if (dev->ud_bdesc != NULL)
			kmem_free(dev->ud_bdesc,
			    UGETW(dev->ud_bdesc->wTotalLength));
		dev->ud_ifaces = NULL;
		dev->ud_cdesc = NULL;
		dev->ud_bdesc = NULL;
		dev->ud_config = USB_UNCONFIG_NO;
	}

	if (index == USB_UNCONFIG_INDEX) {
		/* We are unconfiguring the device, so leave unallocated. */
		DPRINTF("set config 0", 0, 0, 0, 0);
		err = usbd_set_config(dev, USB_UNCONFIG_NO);
		if (err) {
			DPRINTF("setting config=0 failed, err = %d", err,
			    0, 0, 0);
		}
		return err;
	}

	/* Get the short descriptor. */
	err = usbd_get_config_desc(dev, index, &cd);
	if (err) {
		DPRINTF("get_config_desc=%d", err, 0, 0, 0);
		return err;
	}
	len = UGETW(cd.wTotalLength);
	cdp = kmem_alloc(len, KM_SLEEP);
	if (cdp == NULL)
		return USBD_NOMEM;

	/* Get the full descriptor.  Try a few times for slow devices. */
	for (i = 0; i < 3; i++) {
		err = usbd_get_desc(dev, UDESC_CONFIG, index, len, cdp);
		if (!err)
			break;
		usbd_delay_ms(dev, 200);
	}
	if (err) {
		DPRINTF("get_desc=%d", err, 0, 0, 0);
		goto bad;
	}
	if (cdp->bDescriptorType != UDESC_CONFIG) {
		DPRINTF("bad desc %d", cdp->bDescriptorType, 0, 0, 0);
		err = USBD_INVAL;
		goto bad;
	}

	if (USB_IS_SS(dev->ud_speed)) {
		usb_bos_descriptor_t bd;

		/* get short bos desc */
		err = usbd_get_bos_desc(dev, index, &bd);
		if (!err) {
			int blen = UGETW(bd.wTotalLength);
			bdp = kmem_alloc(blen, KM_SLEEP);
			if (bdp == NULL) {
				err = USBD_NOMEM;
				goto bad;
			}

			/* Get the full desc */
			for (i = 0; i < 3; i++) {
				err = usbd_get_desc(dev, UDESC_BOS, index, blen,
				    bdp);
				if (!err)
					break;
				usbd_delay_ms(dev, 200);
			}
			if (err || bdp->bDescriptorType != UDESC_BOS) {
				DPRINTF("error %d or bad desc %d", err,
				    bdp->bDescriptorType, 0, 0);
				kmem_free(bdp, blen);
				bdp = NULL;
			}
		}
	}
	dev->ud_bdesc = bdp;

	/*
	 * Figure out if the device is self or bus powered.
	 */
#if 0 /* XXX various devices don't report the power state correctly */
	selfpowered = 0;
	err = usbd_get_device_status(dev, &ds);
	if (!err && (UGETW(ds.wStatus) & UDS_SELF_POWERED))
		selfpowered = 1;
#endif
	/*
	 * Use the power state in the configuration we are going
	 * to set. This doesn't necessarily reflect the actual
	 * power state of the device; the driver can control this
	 * by choosing the appropriate configuration.
	 */
	selfpowered = !!(cdp->bmAttributes & UC_SELF_POWERED);

	DPRINTF("addr %d cno=%d attr=0x%02x, selfpowered=%d",
	    dev->ud_addr, cdp->bConfigurationValue, cdp->bmAttributes,
	    selfpowered);
	DPRINTF("max power=%d", cdp->bMaxPower * 2, 0, 0, 0);

	/* Check if we have enough power. */
#if 0 /* this is a no-op, see above */
	if ((cdp->bmAttributes & UC_SELF_POWERED) && !selfpowered) {
		if (msg)
			printf("%s: device addr %d (config %d): "
				 "can't set self powered configuration\n",
			       device_xname(dev->ud_bus->bdev), dev->ud_addr,
			       cdp->bConfigurationValue);
		err = USBD_NO_POWER;
		goto bad;
	}
#endif
#ifdef USB_DEBUG
	if (dev->ud_powersrc == NULL) {
		DPRINTF("No power source?", 0, 0, 0, 0);
		err = USBD_IOERROR;
		goto bad;
	}
#endif
	power = cdp->bMaxPower * 2;
	if (power > dev->ud_powersrc->up_power) {
		DPRINTF("power exceeded %d %d", power, dev->ud_powersrc->up_power,
		    0, 0);
		/* XXX print nicer message. */
		if (msg)
			printf("%s: device addr %d (config %d) exceeds power "
				 "budget, %d mA > %d mA\n",
			       device_xname(dev->ud_bus->ub_usbctl), dev->ud_addr,
			       cdp->bConfigurationValue,
			       power, dev->ud_powersrc->up_power);
		err = USBD_NO_POWER;
		goto bad;
	}
	dev->ud_power = power;
	dev->ud_selfpowered = selfpowered;

	/* Set the actual configuration value. */
	DPRINTF("set config %d", cdp->bConfigurationValue, 0, 0, 0);
	err = usbd_set_config(dev, cdp->bConfigurationValue);
	if (err) {
		DPRINTF("setting config=%d failed, error=%d",
		    cdp->bConfigurationValue, err, 0, 0);
		goto bad;
	}

	/* Allocate and fill interface data. */
	nifc = cdp->bNumInterface;
	dev->ud_ifaces = kmem_alloc(nifc * sizeof(struct usbd_interface),
	    KM_SLEEP);
	if (dev->ud_ifaces == NULL) {
		err = USBD_NOMEM;
		goto bad;
	}
	DPRINTFN(5, "dev=%p cdesc=%p", dev, cdp, 0, 0);
	dev->ud_cdesc = cdp;
	dev->ud_config = cdp->bConfigurationValue;
	for (ifcidx = 0; ifcidx < nifc; ifcidx++) {
		err = usbd_fill_iface_data(dev, ifcidx, 0);
		if (err) {
			while (--ifcidx >= 0)
				usbd_free_iface_data(dev, ifcidx);
			goto bad;
		}
	}

	return USBD_NORMAL_COMPLETION;

 bad:
	kmem_free(cdp, len);
	if (bdp != NULL) {
		kmem_free(bdp, UGETW(bdp->wTotalLength));
		dev->ud_bdesc = NULL;
	}
	return err;
}
示例#10
0
文件: usb_subr.c 项目: ryo/netbsd-src
void
usbd_fill_deviceinfo(struct usbd_device *dev, struct usb_device_info *di,
		     int usedev)
{
	struct usbd_port *p;
	int i, j, err;

	di->udi_bus = device_unit(dev->ud_bus->ub_usbctl);
	di->udi_addr = dev->ud_addr;
	di->udi_cookie = dev->ud_cookie;
	usbd_devinfo_vp(dev, di->udi_vendor, sizeof(di->udi_vendor),
	    di->udi_product, sizeof(di->udi_product), usedev, 1);
	usbd_printBCD(di->udi_release, sizeof(di->udi_release),
	    UGETW(dev->ud_ddesc.bcdDevice));
	if (usedev) {
		usbd_status uerr = usbd_get_string(dev,
		    dev->ud_ddesc.iSerialNumber, di->udi_serial);
		if (uerr != USBD_NORMAL_COMPLETION) {
			di->udi_serial[0] = '\0';
		} else {
			usbd_trim_spaces(di->udi_serial);
		}
	} else {
		di->udi_serial[0] = '\0';
		if (dev->ud_serial) {
			strlcpy(di->udi_serial, dev->ud_serial,
			    sizeof(di->udi_serial));
		}
	}

	di->udi_vendorNo = UGETW(dev->ud_ddesc.idVendor);
	di->udi_productNo = UGETW(dev->ud_ddesc.idProduct);
	di->udi_releaseNo = UGETW(dev->ud_ddesc.bcdDevice);
	di->udi_class = dev->ud_ddesc.bDeviceClass;
	di->udi_subclass = dev->ud_ddesc.bDeviceSubClass;
	di->udi_protocol = dev->ud_ddesc.bDeviceProtocol;
	di->udi_config = dev->ud_config;
	di->udi_power = dev->ud_selfpowered ? 0 : dev->ud_power;
	di->udi_speed = dev->ud_speed;

	if (dev->ud_subdevlen > 0) {
		for (i = 0, j = 0; i < dev->ud_subdevlen &&
			     j < USB_MAX_DEVNAMES; i++) {
			if (!dev->ud_subdevs[i])
				continue;
			strncpy(di->udi_devnames[j],
			    device_xname(dev->ud_subdevs[i]), USB_MAX_DEVNAMELEN);
			di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0';
			j++;
		}
	} else {
		j = 0;
	}
	for (/* j is set */; j < USB_MAX_DEVNAMES; j++)
		di->udi_devnames[j][0] = 0;                 /* empty */

	if (!dev->ud_hub) {
		di->udi_nports = 0;
		return;
	}

	const int nports = dev->ud_hub->uh_hubdesc.bNbrPorts;
	for (i = 0; i < __arraycount(di->udi_ports) && i < nports; i++) {
		p = &dev->ud_hub->uh_ports[i];
		if (p->up_dev)
			err = p->up_dev->ud_addr;
		else {
			int s = UGETW(p->up_status.wPortStatus);
			if (s & UPS_PORT_ENABLED)
				err = USB_PORT_ENABLED;
			else if (s & UPS_SUSPEND)
				err = USB_PORT_SUSPENDED;
			/*
			 * Note: UPS_PORT_POWER_SS is available only
			 * on 3.x, and UPS_PORT_POWER is available
			 * only on 2.0 or 1.1.
			 */
			else if (USB_IS_SS(dev->ud_speed) &&
			    (s & UPS_PORT_POWER_SS))
				err = USB_PORT_POWERED;
			else if (s & UPS_PORT_POWER)
				err = USB_PORT_POWERED;
			else
				err = USB_PORT_DISABLED;
		}
		di->udi_ports[i] = err;
	}
	di->udi_nports = nports;
}
示例#11
0
文件: usb_subr.c 项目: ryo/netbsd-src
void
usbd_fill_deviceinfo_old(struct usbd_device *dev, struct usb_device_info_old *di,
                         int usedev)
{
	struct usbd_port *p;
	int i, j, err;

	di->udi_bus = device_unit(dev->ud_bus->ub_usbctl);
	di->udi_addr = dev->ud_addr;
	di->udi_cookie = dev->ud_cookie;
	usbd_devinfo_vp(dev, di->udi_vendor, sizeof(di->udi_vendor),
	    di->udi_product, sizeof(di->udi_product), usedev, 0);
	usbd_printBCD(di->udi_release, sizeof(di->udi_release),
	    UGETW(dev->ud_ddesc.bcdDevice));
	di->udi_vendorNo = UGETW(dev->ud_ddesc.idVendor);
	di->udi_productNo = UGETW(dev->ud_ddesc.idProduct);
	di->udi_releaseNo = UGETW(dev->ud_ddesc.bcdDevice);
	di->udi_class = dev->ud_ddesc.bDeviceClass;
	di->udi_subclass = dev->ud_ddesc.bDeviceSubClass;
	di->udi_protocol = dev->ud_ddesc.bDeviceProtocol;
	di->udi_config = dev->ud_config;
	di->udi_power = dev->ud_selfpowered ? 0 : dev->ud_power;
	di->udi_speed = dev->ud_speed;

	if (dev->ud_subdevlen > 0) {
		for (i = 0, j = 0; i < dev->ud_subdevlen &&
			     j < USB_MAX_DEVNAMES; i++) {
			if (!dev->ud_subdevs[i])
				continue;
			strncpy(di->udi_devnames[j],
			    device_xname(dev->ud_subdevs[i]), USB_MAX_DEVNAMELEN);
			di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0';
			j++;
		}
	} else {
		j = 0;
	}
	for (/* j is set */; j < USB_MAX_DEVNAMES; j++)
		di->udi_devnames[j][0] = 0;		 /* empty */

	if (!dev->ud_hub) {
		di->udi_nports = 0;
		return;
	}

	const int nports = dev->ud_hub->uh_hubdesc.bNbrPorts;
	for (i = 0; i < __arraycount(di->udi_ports) && i < nports;
	     i++) {
		p = &dev->ud_hub->uh_ports[i];
		if (p->up_dev)
			err = p->up_dev->ud_addr;
		else {
			int s = UGETW(p->up_status.wPortStatus);
			if (s & UPS_PORT_ENABLED)
				err = USB_PORT_ENABLED;
			else if (s & UPS_SUSPEND)
				err = USB_PORT_SUSPENDED;
			else if (s & UPS_PORT_POWER)
				err = USB_PORT_POWERED;
			else
				err = USB_PORT_DISABLED;
		}
		di->udi_ports[i] = err;
	}
	di->udi_nports = nports;
}
示例#12
0
文件: usb_subr.c 项目: ryo/netbsd-src
/*
 * Called when a new device has been put in the powered state,
 * but not yet in the addressed state.
 * Get initial descriptor, set the address, get full descriptor,
 * and attach a driver.
 */
usbd_status
usbd_new_device(device_t parent, struct usbd_bus* bus, int depth,
                int speed, int port, struct usbd_port *up)
{
	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
	struct usbd_device *dev, *adev;
	struct usbd_device *hub;
	usb_device_descriptor_t *dd;
	usb_port_status_t ps;
	usbd_status err;
	int addr;
	int i;
	int p;

	DPRINTF("bus=%p port=%d depth=%d speed=%d", bus, port, depth, speed);

	if (bus->ub_methods->ubm_newdev != NULL)
		return (bus->ub_methods->ubm_newdev)(parent, bus, depth, speed,
		    port, up);

	addr = usbd_getnewaddr(bus);
	if (addr < 0) {
		printf("%s: No free USB addresses, new device ignored.\n",
		       device_xname(bus->ub_usbctl));
		return USBD_NO_ADDR;
	}

	dev = kmem_zalloc(sizeof(*dev), KM_SLEEP);
	if (dev == NULL)
		return USBD_NOMEM;

	dev->ud_bus = bus;

	/* Set up default endpoint handle. */
	dev->ud_ep0.ue_edesc = &dev->ud_ep0desc;

	/* Set up default endpoint descriptor. */
	dev->ud_ep0desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;
	dev->ud_ep0desc.bDescriptorType = UDESC_ENDPOINT;
	dev->ud_ep0desc.bEndpointAddress = USB_CONTROL_ENDPOINT;
	dev->ud_ep0desc.bmAttributes = UE_CONTROL;
	/*
	 * temporary, will be fixed after first descriptor fetch
	 * (which uses 64 bytes so it shouldn't be less),
	 * highspeed devices must support 64 byte packets anyway
	 */
	if (speed == USB_SPEED_HIGH || speed == USB_SPEED_FULL)
		USETW(dev->ud_ep0desc.wMaxPacketSize, 64);
	else
		USETW(dev->ud_ep0desc.wMaxPacketSize, USB_MAX_IPACKET);

	dev->ud_ep0desc.bInterval = 0;

	/* doesn't matter, just don't leave it uninitialized */
	dev->ud_ep0.ue_toggle = 0;

	dev->ud_quirks = &usbd_no_quirk;
	dev->ud_addr = USB_START_ADDR;
	dev->ud_ddesc.bMaxPacketSize = 0;
	dev->ud_depth = depth;
	dev->ud_powersrc = up;
	dev->ud_myhub = up->up_parent;

	up->up_dev = dev;

	/* Locate port on upstream high speed hub */
	for (adev = dev, hub = up->up_parent;
	     hub != NULL && hub->ud_speed != USB_SPEED_HIGH;
	     adev = hub, hub = hub->ud_myhub)
		;
	if (hub) {
		for (p = 0; p < hub->ud_hub->uh_hubdesc.bNbrPorts; p++) {
			if (hub->ud_hub->uh_ports[p].up_dev == adev) {
				dev->ud_myhsport = &hub->ud_hub->uh_ports[p];
				goto found;
			}
		}
		panic("usbd_new_device: cannot find HS port");
	found:
		DPRINTFN(1, "high speed port %d", p, 0, 0, 0);
	} else {
		dev->ud_myhsport = NULL;
	}
	dev->ud_speed = speed;
	dev->ud_langid = USBD_NOLANG;
	dev->ud_cookie.cookie = ++usb_cookie_no;

	/* Establish the default pipe. */
	err = usbd_setup_pipe_flags(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
			      &dev->ud_pipe0, USBD_MPSAFE);
	if (err) {
		usbd_remove_device(dev, up);
		return err;
	}

	dd = &dev->ud_ddesc;
	/* Try a few times in case the device is slow (i.e. outside specs.) */
	for (i = 0; i < 10; i++) {
		/* Get the first 8 bytes of the device descriptor. */
		err = usbd_get_initial_ddesc(dev, dd);
		if (!err)
			break;
		usbd_delay_ms(dev, 200);
		if ((i & 3) == 3)
			usbd_reset_port(up->up_parent, port, &ps);
	}
	if (err) {
		DPRINTF("addr=%d, getting first desc failed: %d", addr, err,
		    0, 0);
		usbd_remove_device(dev, up);
		return err;
	}

	/* Windows resets the port here, do likewise */
	if (up->up_parent)
		usbd_reset_port(up->up_parent, port, &ps);

	if (speed == USB_SPEED_HIGH) {
		/* Max packet size must be 64 (sec 5.5.3). */
		if (dd->bMaxPacketSize != USB_2_MAX_CTRL_PACKET) {
#ifdef DIAGNOSTIC
			printf("usbd_new_device: addr=%d bad max packet "
			    "size=%d. adjusting to %d.\n",
			    addr, dd->bMaxPacketSize, USB_2_MAX_CTRL_PACKET);
#endif
			dd->bMaxPacketSize = USB_2_MAX_CTRL_PACKET;
		}
	}

	DPRINTF("adding unit addr=%d, rev=%02x, class=%d, subclass=%d", addr,
	    UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass);
	DPRINTF("protocol=%d, maxpacket=%d, len=%d, speed=%d",
	    dd->bDeviceProtocol, dd->bMaxPacketSize, dd->bLength, dev->ud_speed);

	if (dd->bDescriptorType != UDESC_DEVICE) {
		/* Illegal device descriptor */
		DPRINTF("illegal descriptor %d", dd->bDescriptorType, 0, 0, 0);
		usbd_remove_device(dev, up);
		return USBD_INVAL;
	}

	if (dd->bLength < USB_DEVICE_DESCRIPTOR_SIZE) {
		DPRINTF("bad length %d", dd->bLength, 0, 0, 0);
		usbd_remove_device(dev, up);
		return USBD_INVAL;
	}

	USETW(dev->ud_ep0desc.wMaxPacketSize, dd->bMaxPacketSize);

	/* Re-establish the default pipe with the new MPS. */
	usbd_kill_pipe(dev->ud_pipe0);
	err = usbd_setup_pipe_flags(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
	    &dev->ud_pipe0, USBD_MPSAFE);
	if (err) {
		DPRINTF("setup default pipe failed err %d", err, 0, 0, 0);
		usbd_remove_device(dev, up);
		return err;
	}

	/* Set the address */
	DPRINTFN(5, "setting device address=%d", addr, 0, 0, 0);
	err = usbd_set_address(dev, addr);
	if (err) {
		DPRINTF("set address %d failed, err = %d", addr, err, 0, 0);
		err = USBD_SET_ADDR_FAILED;
		usbd_remove_device(dev, up);
		return err;
	}

	/* Allow device time to set new address */
	usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);
	dev->ud_addr = addr;	/* new device address now */
	bus->ub_devices[addr] = dev;

	/* Re-establish the default pipe with the new address. */
	usbd_kill_pipe(dev->ud_pipe0);
	err = usbd_setup_pipe_flags(dev, 0, &dev->ud_ep0, USBD_DEFAULT_INTERVAL,
	    &dev->ud_pipe0, USBD_MPSAFE);
	if (err) {
		DPRINTF("setup default pipe failed, err = %d", err, 0, 0, 0);
		usbd_remove_device(dev, up);
		return err;
	}

	err = usbd_reload_device_desc(dev);
	if (err) {
		DPRINTF("addr=%d, getting full desc failed, err = %d", addr,
		    err, 0, 0);
		usbd_remove_device(dev, up);
		return err;
	}

	/* Assume 100mA bus powered for now. Changed when configured. */
	dev->ud_power = USB_MIN_POWER;
	dev->ud_selfpowered = 0;

	DPRINTF("new dev (addr %d), dev=%p, parent=%p", addr, dev, parent, 0);

	usbd_get_device_strings(dev);

	usbd_add_dev_event(USB_EVENT_DEVICE_ATTACH, dev);

	if (port == 0) { /* root hub */
		KASSERT(addr == 1);
		usbd_attach_roothub(parent, dev);
		return USBD_NORMAL_COMPLETION;
	}

	err = usbd_probe_and_attach(parent, dev, port, addr);
	if (err) {
		usbd_remove_device(dev, up);
		return err;
	}

	return USBD_NORMAL_COMPLETION;
}
示例#13
0
int
uirda_set_params(void *h, struct irda_params *p)
{
	struct uirda_softc *sc = h;
	usbd_status err;
	int i;
	u_int8_t hdr;
	u_int32_t n;
	u_int mask;

	DPRINTF(("%s: sc=%p, speed=%d ebofs=%d maxsize=%d\n", __func__,
		 sc, p->speed, p->ebofs, p->maxsize));

	if (sc->sc_dying)
		return (EIO);

	hdr = 0;
	if (p->ebofs != sc->sc_params.ebofs) {
		/* round up ebofs */
		mask = 1 /* sc->sc_irdadesc.bmAdditionalBOFs*/;
		DPRINTF(("u.s.p.: mask=0x%x, sc->ebofs=%d, p->ebofs=%d\n",
			mask, sc->sc_params.ebofs, p->ebofs));
		for (i = 0; i < UIRDA_NEBOFS; i++) {
			DPRINTF(("u.s.p.: u_e[%d].mask=0x%x, count=%d\n",
				i, uirda_ebofs[i].mask, uirda_ebofs[i].count));
			if ((mask & uirda_ebofs[i].mask) &&
			    uirda_ebofs[i].count >= p->ebofs) {
				hdr = uirda_ebofs[i].header;
				goto found1;
			}
		}
		for (i = 0; i < UIRDA_NEBOFS; i++) {
			DPRINTF(("u.s.p.: u_e[%d].mask=0x%x, count=%d\n",
				i, uirda_ebofs[i].mask, uirda_ebofs[i].count));
			if ((mask & uirda_ebofs[i].mask)) {
				hdr = uirda_ebofs[i].header;
				goto found1;
			}
		}
		/* no good value found */
		return (EINVAL);
	found1:
		DPRINTF(("uirda_set_params: ebofs hdr=0x%02x\n", hdr));
		;

	}
	if (hdr != 0 || p->speed != sc->sc_params.speed) {
		/* find speed */
		mask = UGETW(sc->sc_irdadesc.wBaudRate);
		for (i = 0; i < UIRDA_NSPEEDS; i++) {
			if ((mask & uirda_speeds[i].mask) &&
			    uirda_speeds[i].speed == p->speed) {
				hdr |= uirda_speeds[i].header;
				goto found2;
			}
		}
		/* no good value found */
		return (EINVAL);
	found2:
		DPRINTF(("uirda_set_params: speed hdr=0x%02x\n", hdr));
		;
	}
	if (p->maxsize != sc->sc_params.maxsize) {
		if (p->maxsize > IRDA_MAX_FRAME_SIZE)
			return (EINVAL);
		sc->sc_params.maxsize = p->maxsize;
#if 0
		DPRINTF(("%s: new buffers, old size=%d\n", __func__,
			 sc->sc_params.maxsize));
		if (p->maxsize > 10000 || p < 0) /* XXX */
			return (EINVAL);

		/* Change the write buffer */
		mutex_enter(&sc->sc_wr_buf_lk);
		if (sc->sc_wr_buf != NULL)
			usbd_free_buffer(sc->sc_wr_xfer);
		sc->sc_wr_buf = usbd_alloc_buffer(sc->sc_wr_xfer, p->maxsize+1);
		mutex_exit(&sc->sc_wr_buf_lk);
		if (sc->sc_wr_buf == NULL)
			return (ENOMEM);

		/* Change the read buffer */
		mutex_enter(&sc->sc_rd_buf_lk);
		usbd_abort_pipe(sc->sc_rd_pipe);
		if (sc->sc_rd_buf != NULL)
			usbd_free_buffer(sc->sc_rd_xfer);
		sc->sc_rd_buf = usbd_alloc_buffer(sc->sc_rd_xfer, p->maxsize+1);
		sc->sc_rd_count = 0;
		if (sc->sc_rd_buf == NULL) {
			mutex_exit(&sc->sc_rd_buf_lk);
			return (ENOMEM);
		}
		sc->sc_params.maxsize = p->maxsize;
		err = uirda_start_read(sc); /* XXX check */
		mutex_exit(&sc->sc_rd_buf_lk);
#endif
	}
	if (hdr != 0 && hdr != sc->sc_wr_hdr) {
		/*
		 * A change has occurred, transmit a 0 length frame with
		 * the new settings.  The 0 length frame is not sent to the
		 * device.
		 */
		DPRINTF(("%s: sc=%p setting header 0x%02x\n",
			 __func__, sc, hdr));
		sc->sc_wr_hdr = hdr;
		mutex_enter(&sc->sc_wr_buf_lk);
		sc->sc_wr_buf[0] = hdr;
		n = UIRDA_OUTPUT_HEADER_SIZE;
		err = usbd_bulk_transfer(sc->sc_wr_xfer, sc->sc_wr_pipe,
			  USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
			  UIRDA_WR_TIMEOUT, sc->sc_wr_buf, &n, "uirdast");
		if (err) {
			aprint_error_dev(sc->sc_dev, "set failed, err=%d\n",
			    err);
			usbd_clear_endpoint_stall(sc->sc_wr_pipe);
		}
		mutex_exit(&sc->sc_wr_buf_lk);
	}

	sc->sc_params = *p;

	return (0);
}
示例#14
0
static void
udsir_attach(device_t parent, device_t self, void *aux)
{
	struct udsir_softc *sc = device_private(self);
	struct usbif_attach_arg *uaa = aux;
	usbd_device_handle dev = uaa->device;
	usbd_interface_handle iface = uaa->iface;
	char *devinfop;
	usb_endpoint_descriptor_t *ed;
	uint8_t epcount;
	int i;
	struct ir_attach_args ia;

	DPRINTFN(10, ("udsir_attach: sc=%p\n", sc));

	sc->sc_dev = self;

	aprint_naive("\n");
	aprint_normal("\n");

	devinfop = usbd_devinfo_alloc(dev, 0);
	aprint_normal_dev(self, "%s\n", devinfop);
	usbd_devinfo_free(devinfop);

	sc->sc_udev = dev;
	sc->sc_iface = iface;

	epcount = 0;
	(void)usbd_endpoint_count(iface, &epcount);

	sc->sc_rd_addr = -1;
	sc->sc_wr_addr = -1;
	for (i = 0; i < epcount; i++) {
		ed = usbd_interface2endpoint_descriptor(iface, i);
		if (ed == NULL) {
			aprint_error_dev(self, "couldn't get ep %d\n", i);
			return;
		}
		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
			sc->sc_rd_addr = ed->bEndpointAddress;
			sc->sc_rd_maxpsz = UGETW(ed->wMaxPacketSize);
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
			sc->sc_wr_addr = ed->bEndpointAddress;
			sc->sc_wr_maxpsz = UGETW(ed->wMaxPacketSize);
		}
	}
	if (sc->sc_rd_addr == -1 || sc->sc_wr_addr == -1) {
		aprint_error_dev(self, "missing endpoint\n");
		return;
	}

	DPRINTFN(10, ("udsir_attach: %p\n", sc->sc_udev));

	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
			   sc->sc_dev);

	ia.ia_type = IR_TYPE_IRFRAME;
	ia.ia_methods = &udsir_methods;
	ia.ia_handle = sc;

	sc->sc_child = config_found(self, &ia, ir_print);
	selinit(&sc->sc_rd_sel);
	selinit(&sc->sc_wr_sel);

	return;
}
示例#15
0
void
umsm_intr(struct usbd_xfer *xfer, void *priv,
	usbd_status status)
{
	struct umsm_softc *sc = priv;
	struct usb_cdc_notification *buf;
	u_char mstatus;

	buf = (struct usb_cdc_notification *)sc->sc_intr_buf;
	if (usbd_is_dying(sc->sc_udev))
		return;

	if (status != USBD_NORMAL_COMPLETION) {
		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
			return;

		DPRINTF(("%s: umsm_intr: abnormal status: %s\n",
		    sc->sc_dev.dv_xname, usbd_errstr(status)));
		usbd_clear_endpoint_stall_async(sc->sc_intr_pipe);
		return;
	}

	if (buf->bmRequestType != UCDC_NOTIFICATION) {
#if 1 /* test */
		printf("%s: this device is not using CDC notify message in intr pipe.\n"
		    "Please send your dmesg to <*****@*****.**>, thanks.\n",
		    sc->sc_dev.dv_xname);
		printf("%s: intr buffer 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
		    sc->sc_dev.dv_xname,
		    sc->sc_intr_buf[0], sc->sc_intr_buf[1],
		    sc->sc_intr_buf[2], sc->sc_intr_buf[3],
		    sc->sc_intr_buf[4], sc->sc_intr_buf[5],
		    sc->sc_intr_buf[6]);
#else
		DPRINTF(("%s: umsm_intr: unknown message type(0x%02x)\n",
		    sc->sc_dev.dv_xname, buf->bmRequestType));
#endif
		return;
	}

	if (buf->bNotification == UCDC_N_SERIAL_STATE) {
		/* invalid message length, discard it */
		if (UGETW(buf->wLength) != 2)
			return;
		/* XXX: sc_lsr is always 0 */
		sc->sc_lsr = sc->sc_msr = 0;
		mstatus = buf->data[0];
		if (ISSET(mstatus, UCDC_N_SERIAL_RI))
			sc->sc_msr |= UMSR_RI;
		if (ISSET(mstatus, UCDC_N_SERIAL_DSR))
			sc->sc_msr |= UMSR_DSR;
		if (ISSET(mstatus, UCDC_N_SERIAL_DCD))
			sc->sc_msr |= UMSR_DCD;
	} else if (buf->bNotification != UCDC_N_CONNECTION_SPEED_CHANGE) {
		DPRINTF(("%s: umsm_intr: unknown notify message (0x%02x)\n",
		    sc->sc_dev.dv_xname, buf->bNotification));
		return;
	}

	ucom_status_change((struct ucom_softc *)sc->sc_subdev);
}
示例#16
0
文件: usb_subr.c 项目: ryo/netbsd-src
static usbd_status
usbd_attachinterfaces(device_t parent, struct usbd_device *dev,
		      int port, const int *locators)
{
	USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
	struct usbif_attach_arg uiaa;
	int ilocs[USBIFIFCF_NLOCS];
	usb_device_descriptor_t *dd = &dev->ud_ddesc;
	int nifaces;
	struct usbd_interface **ifaces;
	int i, j, loc;
	device_t dv;

	nifaces = dev->ud_cdesc->bNumInterface;
	ifaces = kmem_zalloc(nifaces * sizeof(*ifaces), KM_SLEEP);
	if (!ifaces)
		return USBD_NOMEM;
	for (i = 0; i < nifaces; i++) {
		if (!dev->ud_subdevs[i]) {
			ifaces[i] = &dev->ud_ifaces[i];
		}
		DPRINTF("interface %d %p", i, ifaces[i], 0, 0);
	}


	uiaa.uiaa_device = dev;
	uiaa.uiaa_port = port;
	uiaa.uiaa_vendor = UGETW(dd->idVendor);
	uiaa.uiaa_product = UGETW(dd->idProduct);
	uiaa.uiaa_release = UGETW(dd->bcdDevice);
	uiaa.uiaa_configno = dev->ud_cdesc->bConfigurationValue;
	uiaa.uiaa_ifaces = ifaces;
	uiaa.uiaa_nifaces = nifaces;
	ilocs[USBIFIFCF_PORT] = uiaa.uiaa_port;
	ilocs[USBIFIFCF_VENDOR] = uiaa.uiaa_vendor;
	ilocs[USBIFIFCF_PRODUCT] = uiaa.uiaa_product;
	ilocs[USBIFIFCF_RELEASE] = uiaa.uiaa_release;
	ilocs[USBIFIFCF_CONFIGURATION] = uiaa.uiaa_configno;

	for (i = 0; i < nifaces; i++) {
		if (!ifaces[i]) {
			DPRINTF("interface %d claimed", i, 0, 0, 0);
			continue; /* interface already claimed */
		}
		uiaa.uiaa_iface = ifaces[i];
		uiaa.uiaa_class = ifaces[i]->ui_idesc->bInterfaceClass;
		uiaa.uiaa_subclass = ifaces[i]->ui_idesc->bInterfaceSubClass;
		uiaa.uiaa_proto = ifaces[i]->ui_idesc->bInterfaceProtocol;
		uiaa.uiaa_ifaceno = ifaces[i]->ui_idesc->bInterfaceNumber;

		DPRINTF("searching for interface %d...", i, 0, 0, 0);
		DPRINTF("class %x subclass %x proto %x ifaceno %d",
		    uiaa.uiaa_class, uiaa.uiaa_subclass, uiaa.uiaa_proto,
		    uiaa.uiaa_ifaceno);
		ilocs[USBIFIFCF_INTERFACE] = uiaa.uiaa_ifaceno;
		if (locators != NULL) {
			loc = locators[USBIFIFCF_CONFIGURATION];
			if (loc != USBIFIFCF_CONFIGURATION_DEFAULT &&
			    loc != uiaa.uiaa_configno)
				continue;
			loc = locators[USBIFIFCF_INTERFACE];
			if (loc != USBIFIFCF_INTERFACE_DEFAULT &&
			    loc != uiaa.uiaa_ifaceno)
				continue;
		}
		KERNEL_LOCK(1, NULL);
		dv = config_found_sm_loc(parent, "usbifif", ilocs, &uiaa,
					 usbd_ifprint, config_stdsubmatch);
		KERNEL_UNLOCK_ONE(NULL);
		if (!dv)
			continue;

		usbd_serialnumber(dv, dev);

		/* claim */
		ifaces[i] = NULL;
		/* account for ifaces claimed by the driver behind our back */
		for (j = 0; j < nifaces; j++) {

			if (!ifaces[j] && !dev->ud_subdevs[j]) {
				DPRINTF("interface %d claimed behind our back",
				    j, 0, 0, 0);
				dev->ud_subdevs[j] = dv;
				dev->ud_nifaces_claimed++;
			}
		}
	}

	kmem_free(ifaces, nifaces * sizeof(*ifaces));
	return USBD_NORMAL_COMPLETION;
}
示例#17
0
/*
 ****************************************************************
 *	Varre as portas de uma unidade				*
 ****************************************************************
 */
int
uhub_explore (struct usbd_device *dev)
{
	struct usb_hub_descriptor	*hd = &dev->hub->hubdesc;
	struct uhub_softc		*sc = dev->hub->hubsoftc;
	struct usbd_port		*up;
	int				err, speed;
	int				port, change, status;

#ifdef	USB_MSG
	printf ("uhub_explore (%s)\n", sc->sc_dev->nameunit);
	printf ("uhub_explore: dev= %P addr = %d\n", dev, dev->address);
#endif	USB_MSG

	if (sc->sc_running == 0)
		return (USBD_NOT_STARTED);

	if (dev->depth > USB_HUB_MAX_DEPTH)
		return (USBD_TOO_DEEP);

	for (port = 1; port <= hd->bNbrPorts; port++)
	{
		up = &dev->hub->ports[port - 1];

		if (err = usbd_get_port_status (dev, port, &up->status))
		{
			printf
			(	"uhub_explore (%s): erro ao ler o estado da porta %d (%s)\n",
				sc->sc_dev->nameunit, port, usbd_errstr (err)
			);
			continue;
		}

		status = UGETW (up->status.wPortStatus);
		change = UGETW (up->status.wPortChange);

#ifdef	USB_MSG
		printf
		(	"uhub_explore (%s) porta %d status = 0x%04X change = 0x%04X\n",
			sc->sc_dev->nameunit, port, status, change
		);
#endif	USB_MSG

		if (change & UPS_C_PORT_ENABLED)
		{
#ifdef	USB_MSG
			printf ("uhub_explore: C_PORT_ENABLED\n");
#endif	USB_MSG

			usbd_clear_port_feature (dev, port, UHF_C_PORT_ENABLE);

			if   (change & UPS_C_CONNECT_STATUS)
			{
				/* Ignore the port error if the device vanished. */
#ifdef	USB_MSG
				printf
				(	"uhub_explore (%s): ignorando erro, porta %d\n",
					sc->sc_dev->nameunit, port
				);
#endif	USB_MSG
			}
			elif (status & UPS_PORT_ENABLED)
			{
				printf
				(	"uhub_explore (%s): mudança inválida de habilitação, porta %d\n",
					sc->sc_dev->nameunit, port
				);
			}
			else
			{
				/* Port error condition */

				if (up->restartcnt)		/* no message first time */
示例#18
0
文件: uvscom.c 项目: sofuture/bitrig
void
uvscom_attach(struct device *parent, struct device *self, void *aux)
{
	struct uvscom_softc *sc = (struct uvscom_softc *)self;
	struct usb_attach_arg *uaa = aux;
	usbd_device_handle dev = uaa->device;
	usb_config_descriptor_t *cdesc;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	const char *devname = sc->sc_dev.dv_xname;
	usbd_status err;
	int i;
	struct ucom_attach_args uca;

        sc->sc_udev = dev;

	DPRINTF(("uvscom attach: sc = %p\n", sc));

	/* initialize endpoints */
	uca.bulkin = uca.bulkout = -1;
	sc->sc_intr_number = -1;
	sc->sc_intr_pipe = NULL;

	/* Move the device into the configured state. */
	err = usbd_set_config_index(dev, UVSCOM_CONFIG_INDEX, 1);
	if (err) {
		printf("%s: failed to set configuration, err=%s\n",
			devname, usbd_errstr(err));
		sc->sc_dying = 1;
		return;
	}

	/* get the config descriptor */
	cdesc = usbd_get_config_descriptor(sc->sc_udev);

	if (cdesc == NULL) {
		printf("%s: failed to get configuration descriptor\n",
			sc->sc_dev.dv_xname);
		sc->sc_dying = 1;
		return;
	}

	/* get the common interface */
	err = usbd_device2interface_handle(dev, UVSCOM_IFACE_INDEX,
					   &sc->sc_iface);
	if (err) {
		printf("%s: failed to get interface, err=%s\n",
			devname, usbd_errstr(err));
		sc->sc_dying = 1;
		return;
	}

	id = usbd_get_interface_descriptor(sc->sc_iface);
	sc->sc_iface_number = id->bInterfaceNumber;

	/* Find endpoints */
	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
		if (ed == NULL) {
			printf("%s: no endpoint descriptor for %d\n",
				sc->sc_dev.dv_xname, i);
			sc->sc_dying = 1;
			return;
		}

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			uca.bulkin = ed->bEndpointAddress;
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			uca.bulkout = ed->bEndpointAddress;
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
			sc->sc_intr_number = ed->bEndpointAddress;
			sc->sc_isize = UGETW(ed->wMaxPacketSize);
		}
	}

	if (uca.bulkin == -1) {
		printf("%s: Could not find data bulk in\n",
			sc->sc_dev.dv_xname);
		sc->sc_dying = 1;
		return;
	}
	if (uca.bulkout == -1) {
		printf("%s: Could not find data bulk out\n",
			sc->sc_dev.dv_xname);
		sc->sc_dying = 1;
		return;
	}
	if (sc->sc_intr_number == -1) {
		printf("%s: Could not find interrupt in\n",
			sc->sc_dev.dv_xname);
		sc->sc_dying = 1;
		return;
	}

	sc->sc_dtr = sc->sc_rts = 0;
	sc->sc_lcr = UVSCOM_LINE_INIT;

	uca.portno = UCOM_UNK_PORTNO;
	/* bulkin, bulkout set above */
	uca.ibufsize = UVSCOMIBUFSIZE;
	uca.obufsize = UVSCOMOBUFSIZE;
	uca.ibufsizepad = UVSCOMIBUFSIZE;
	uca.opkthdrlen = 0;
	uca.device = dev;
	uca.iface = sc->sc_iface;
	uca.methods = &uvscom_methods;
	uca.arg = sc;
	uca.info = NULL;

	err = uvscom_reset(sc);

	if (err) {
		printf("%s: reset failed, %s\n", sc->sc_dev.dv_xname,
			usbd_errstr(err));
		sc->sc_dying = 1;
		return;
	}

	DPRINTF(("uvscom: in = 0x%x out = 0x%x intr = 0x%x\n",
		 ucom->sc_bulkin_no, ucom->sc_bulkout_no, sc->sc_intr_number));

	DPRINTF(("uplcom: in=0x%x out=0x%x intr=0x%x\n",
			uca.bulkin, uca.bulkout, sc->sc_intr_number ));
	sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
}
示例#19
0
void
uhidev_attach(struct device *parent, struct device *self, void *aux)
{
	struct uhidev_softc *sc = (struct uhidev_softc *)self;
	struct usb_attach_arg *uaa = aux;
	usbd_interface_handle iface = uaa->iface;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	struct uhidev_attach_arg uha;
	struct uhidev *dev;
	int size, nrepid, repid, repsz;
	int repsizes[256];
	int i;
	void *desc;
	const void *descptr;
	usbd_status err;

	sc->sc_udev = uaa->device;
	sc->sc_iface = iface;
	id = usbd_get_interface_descriptor(iface);

	(void)usbd_set_idle(iface, 0, 0);
#if 0

	qflags = usbd_get_quirks(sc->sc_udev)->uq_flags;
	if ((qflags & UQ_NO_SET_PROTO) == 0 &&
	    id->bInterfaceSubClass != UISUBCLASS_BOOT)
		(void)usbd_set_protocol(iface, 1);
#endif

	sc->sc_iep_addr = sc->sc_oep_addr = -1;
	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(iface, i);
		if (ed == NULL) {
			printf("%s: could not read endpoint descriptor\n",
			    sc->sc_dev.dv_xname);
			sc->sc_dying = 1;
			return;
		}

		DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d "
		    "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d"
		    " bInterval=%d\n",
		    ed->bLength, ed->bDescriptorType,
		    ed->bEndpointAddress & UE_ADDR,
		    UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out",
		    ed->bmAttributes & UE_XFERTYPE,
		    UGETW(ed->wMaxPacketSize), ed->bInterval));

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
			sc->sc_iep_addr = ed->bEndpointAddress;
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
		    (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) {
			sc->sc_oep_addr = ed->bEndpointAddress;
		} else {
			printf("%s: unexpected endpoint\n", sc->sc_dev.dv_xname);
			sc->sc_dying = 1;
			return;
		}
	}

	/*
	 * Check that we found an input interrupt endpoint. The output interrupt
	 * endpoint is optional
	 */
	if (sc->sc_iep_addr == -1) {
		printf("%s: no input interrupt endpoint\n", sc->sc_dev.dv_xname);
		sc->sc_dying = 1;
		return;
	}

	/* XXX need to extend this */
	descptr = NULL;
	if (uaa->vendor == USB_VENDOR_WACOM) {
		static uByte reportbuf[] = {2, 2, 2};

		/* The report descriptor for the Wacom Graphire is broken. */
		switch (uaa->product) {
		case USB_PRODUCT_WACOM_GRAPHIRE:
			size = sizeof uhid_graphire_report_descr;
			descptr = uhid_graphire_report_descr;
			break;
		case USB_PRODUCT_WACOM_GRAPHIRE3_4X5:
		case USB_PRODUCT_WACOM_GRAPHIRE4_4X5:
			usbd_set_report(uaa->iface, UHID_FEATURE_REPORT, 2,
			    &reportbuf, sizeof reportbuf);
			size = sizeof uhid_graphire3_4x5_report_descr;
			descptr = uhid_graphire3_4x5_report_descr;
			break;
		default:
			/* Keep descriptor */
			break;
		}
	}

	if (descptr) {
		desc = malloc(size, M_USBDEV, M_NOWAIT);
		if (desc == NULL)
			err = USBD_NOMEM;
		else {
			err = USBD_NORMAL_COMPLETION;
			memcpy(desc, descptr, size);
		}
	} else {
		desc = NULL;
		err = usbd_read_report_desc(uaa->iface, &desc, &size, M_USBDEV);
	}
	if (err) {
		printf("%s: no report descriptor\n", sc->sc_dev.dv_xname);
		sc->sc_dying = 1;
		return;
	}

	sc->sc_repdesc = desc;
	sc->sc_repdesc_size = size;

	uha.uaa = uaa;
	nrepid = uhidev_maxrepid(desc, size);
	if (nrepid < 0)
		return;
	printf("%s: iclass %d/%d", sc->sc_dev.dv_xname,
	    id->bInterfaceClass, id->bInterfaceSubClass);
	if (nrepid > 0)
		printf(", %d report id%s", nrepid,
		    nrepid > 1 ? "s" : "");
	printf("\n");
	nrepid++;
	sc->sc_subdevs = malloc(nrepid * sizeof(struct device *),
	    M_USBDEV, M_NOWAIT | M_ZERO);
	if (sc->sc_subdevs == NULL) {
		printf("%s: no memory\n", sc->sc_dev.dv_xname);
		return;
	}
	sc->sc_nrepid = nrepid;
	sc->sc_isize = 0;

	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
			   &sc->sc_dev);

	for (repid = 0; repid < nrepid; repid++) {
		repsz = hid_report_size(desc, size, hid_input, repid);
		DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz));
		repsizes[repid] = repsz;
		if (repsz > 0) {
			if (repsz > sc->sc_isize)
				sc->sc_isize = repsz;
		}
	}
	sc->sc_isize += nrepid != 1;	/* space for report ID */
	DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize));

	uha.parent = sc;
	for (repid = 0; repid < nrepid; repid++) {
		DPRINTF(("uhidev_match: try repid=%d\n", repid));
		if (hid_report_size(desc, size, hid_input, repid) == 0 &&
		    hid_report_size(desc, size, hid_output, repid) == 0 &&
		    hid_report_size(desc, size, hid_feature, repid) == 0) {
			;	/* already NULL in sc->sc_subdevs[repid] */
		} else {
			uha.reportid = repid;
			dev = (struct uhidev *)config_found_sm(self, &uha,
			                           uhidevprint, uhidevsubmatch);
			sc->sc_subdevs[repid] = dev;
			if (dev != NULL) {
				dev->sc_in_rep_size = repsizes[repid];
#ifdef DIAGNOSTIC
				DPRINTF(("uhidev_match: repid=%d dev=%p\n",
					 repid, dev));
				if (dev->sc_intr == NULL) {
					DPRINTF(("%s: sc_intr == NULL\n",
					       sc->sc_dev.dv_xname));
					return;
				}
#endif
			}
		}
	}
}
示例#20
0
usbd_status
uhub_explore(usbd_device_handle dev)
{
	usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
	device_t self = dev->hub->hubdev;
	struct uhub_softc *sc = device_get_softc(self);
	struct usbd_port *up;
	usbd_status err;
	int speed;
	int port;
	int change, status;

	DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));

	if (!sc->sc_running)
		return (USBD_NOT_STARTED);

	/* Ignore hubs that are too deep. */
	if (dev->depth > USB_HUB_MAX_DEPTH)
		return (USBD_TOO_DEEP);

	for(port = 1; port <= hd->bNbrPorts; port++) {
		up = &dev->hub->ports[port-1];
		err = usbd_get_port_status(dev, port, &up->status);
		if (err) {
			DPRINTF(("uhub_explore: get port status failed, "
				 "error=%s\n", usbd_errstr(err)));
			continue;
		}
		status = UGETW(up->status.wPortStatus);
		change = UGETW(up->status.wPortChange);
		DPRINTFN(3,("uhub_explore: %s port %d status 0x%04x 0x%04x\n",
			    device_get_nameunit(self), port, status, change));
		if (change & UPS_C_PORT_ENABLED) {
			DPRINTF(("uhub_explore: C_PORT_ENABLED 0x%x\n", change));
			usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
			if (change & UPS_C_CONNECT_STATUS) {
				/* Ignore the port error if the device
				   vanished. */
			} else if (status & UPS_PORT_ENABLED) {
				device_printf(self,
				    "illegal enable change, port %d\n", port);
			} else {
				/* Port error condition. */
				if (up->restartcnt) /* no message first time */
					device_printf(self,
					    "port error, restarting "
					    "port %d\n", port);

				if (up->restartcnt++ < USBD_RESTART_MAX)
					goto disco;
				else
					device_printf(self,
					    "port error, giving up "
					    "port %d\n", port);
			}
		}
		if (!(change & UPS_C_CONNECT_STATUS)) {
			DPRINTFN(3,("uhub_explore: port=%d !C_CONNECT_"
				    "STATUS\n", port));
			/* No status change, just do recursive explore. */
			if (up->device != NULL && up->device->hub != NULL)
				up->device->hub->explore(up->device);
#if 0 && defined(DIAGNOSTIC)
			if (up->device == NULL &&
			    (status & UPS_CURRENT_CONNECT_STATUS))
				device_printf(self,
				    "connected, no device\n");
#endif
			continue;
		}

		/* We have a connect status change, handle it. */

		DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
			 dev->address, port));
		usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
		/*usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);*/
		/*
		 * If there is already a device on the port the change status
		 * must mean that is has disconnected.  Looking at the
		 * current connect status is not enough to figure this out
		 * since a new unit may have been connected before we handle
		 * the disconnect.
		 */
	disco:
		if (up->device != NULL) {
			/* Disconnected */
			DPRINTF(("uhub_explore: device addr=%d disappeared "
				 "on port %d\n", up->device->address, port));
			usb_disconnect_port(up, self);
			usbd_clear_port_feature(dev, port,
						UHF_C_PORT_CONNECTION);
		}
		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
			/* Nothing connected, just ignore it. */
			DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
				    "_STATUS\n", port));
			continue;
		}

		/* Connected */

		if (!(status & UPS_PORT_POWER))
			device_printf(self,
			    "strange, connected port %d has no power\n",
			    port);

		/* Wait for maximum device power up time. */
		usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);

		/* Reset port, which implies enabling it. */
		if (usbd_reset_port(dev, port, &up->status)) {
			device_printf(self,
			    "port %d reset failed\n", port);
			continue;
		}
		/* Get port status again, it might have changed during reset */
		err = usbd_get_port_status(dev, port, &up->status);
		if (err) {
			DPRINTF(("uhub_explore: get port status failed, "
				 "error=%s\n", usbd_errstr(err)));
			continue;
		}
		status = UGETW(up->status.wPortStatus);
		change = UGETW(up->status.wPortChange);
		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
			/* Nothing connected, just ignore it. */
#ifdef DIAGNOSTIC
			device_printf(self,
			    "port %d, device disappeared after reset\n",
			    port);
#endif
			continue;
		}

#if 0
		if (UHUB_IS_HIGH_SPEED(sc) && !(status & UPS_HIGH_SPEED)) {
			device_printf(self,
			    "port %d, transaction translation not "
			    "implemented, low/full speed device ignored\n",
			    port);
			continue;
		}
#endif

		/* Figure out device speed */
		if (status & UPS_HIGH_SPEED)
			speed = USB_SPEED_HIGH;
		else if (status & UPS_LOW_SPEED)
			speed = USB_SPEED_LOW;
		else
			speed = USB_SPEED_FULL;
		/* Get device info and set its address. */
		err = usbd_new_device(self, dev->bus,
				      dev->depth + 1, speed, port, up);
		/* XXX retry a few times? */
		if (err) {
			DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
				     "error=%s\n", usbd_errstr(err)));
			/* Avoid addressing problems by disabling. */
			/* usbd_reset_port(dev, port, &up->status); */

			/*
			 * The unit refused to accept a new address, or had
			 * some other serious problem.  Since we cannot leave
			 * at 0 we have to disable the port instead.
			 */
			device_printf(self,
			    "device problem (%s), disabling port %d\n",
			    usbd_errstr(err), port);
			usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
		} else {
			/* The port set up succeeded, reset error count. */
			up->restartcnt = 0;

			if (up->device->hub)
				up->device->hub->explore(up->device);
		}
	}
	return (USBD_NORMAL_COMPLETION);
}
示例#21
0
文件: if_kue.c 项目: MarginC/kame
Static int
kue_load_fw(struct kue_softc *sc)
{
	usb_device_descriptor_t dd;
	usbd_status		err;

	DPRINTFN(1,("%s: %s: enter\n", USBDEVNAME(sc->kue_dev), __func__));

	/*
	 * First, check if we even need to load the firmware.
	 * If the device was still attached when the system was
	 * rebooted, it may already have firmware loaded in it.
	 * If this is the case, we don't need to do it again.
	 * And in fact, if we try to load it again, we'll hang,
	 * so we have to avoid this condition if we don't want
	 * to look stupid.
	 *
         * We can test this quickly by checking the bcdRevision
         * code. The NIC will return a different revision code if
         * it's probed while the firmware is still loaded and
         * running.
         */
	if (usbd_get_device_desc(sc->kue_udev, &dd))
		return (EIO);
        if (UGETW(dd.bcdDevice) == KUE_WARM_REV) {
		printf("%s: warm boot, no firmware download\n",
		       USBDEVNAME(sc->kue_dev));
		return (0);
	}

	printf("%s: cold boot, downloading firmware\n",
	       USBDEVNAME(sc->kue_dev));

	/* Load code segment */
	DPRINTFN(1,("%s: kue_load_fw: download code_seg\n",
		    USBDEVNAME(sc->kue_dev)));
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, (void *)kue_code_seg, sizeof(kue_code_seg));
	if (err) {
		printf("%s: failed to load code segment: %s\n",
		    USBDEVNAME(sc->kue_dev), usbd_errstr(err));
			return (EIO);
	}

	/* Load fixup segment */
	DPRINTFN(1,("%s: kue_load_fw: download fix_seg\n",
		    USBDEVNAME(sc->kue_dev)));
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, (void *)kue_fix_seg, sizeof(kue_fix_seg));
	if (err) {
		printf("%s: failed to load fixup segment: %s\n",
		    USBDEVNAME(sc->kue_dev), usbd_errstr(err));
			return (EIO);
	}

	/* Send trigger command. */
	DPRINTFN(1,("%s: kue_load_fw: download trig_seg\n",
		    USBDEVNAME(sc->kue_dev)));
	err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
	    0, (void *)kue_trig_seg, sizeof(kue_trig_seg));
	if (err) {
		printf("%s: failed to load trigger segment: %s\n",
		    USBDEVNAME(sc->kue_dev), usbd_errstr(err));
			return (EIO);
	}

	usbd_delay_ms(sc->kue_udev, 10);

	/*
	 * Reload device descriptor.
	 * Why? The chip without the firmware loaded returns
	 * one revision code. The chip with the firmware
	 * loaded and running returns a *different* revision
	 * code. This confuses the quirk mechanism, which is
	 * dependent on the revision data.
	 */
	(void)usbd_reload_device_desc(sc->kue_udev);

	DPRINTFN(1,("%s: %s: done\n", USBDEVNAME(sc->kue_dev), __func__));

	/* Reset the adapter. */
	kue_reset(sc);

	return (0);
}
示例#22
0
文件: ng_ubt.c 项目: 2asoft/freebsd
static int
ubt_attach(device_t dev)
{
	struct usb_attach_arg		*uaa = device_get_ivars(dev);
	struct ubt_softc		*sc = device_get_softc(dev);
	struct usb_endpoint_descriptor	*ed;
	struct usb_interface_descriptor *id;
	struct usb_interface		*iface;
	uint16_t			wMaxPacketSize;
	uint8_t				alt_index, i, j;
	uint8_t				iface_index[2] = { 0, 1 };

	device_set_usb_desc(dev);

	sc->sc_dev = dev;
	sc->sc_debug = NG_UBT_WARN_LEVEL;

	/* 
	 * Create Netgraph node
	 */

	if (ng_make_node_common(&typestruct, &sc->sc_node) != 0) {
		UBT_ALERT(sc, "could not create Netgraph node\n");
		return (ENXIO);
	}

	/* Name Netgraph node */
	if (ng_name_node(sc->sc_node, device_get_nameunit(dev)) != 0) {
		UBT_ALERT(sc, "could not name Netgraph node\n");
		NG_NODE_UNREF(sc->sc_node);
		return (ENXIO);
	}
	NG_NODE_SET_PRIVATE(sc->sc_node, sc);
	NG_NODE_FORCE_WRITER(sc->sc_node);

	/*
	 * Initialize device softc structure
	 */

	/* initialize locks */
	mtx_init(&sc->sc_ng_mtx, "ubt ng", NULL, MTX_DEF);
	mtx_init(&sc->sc_if_mtx, "ubt if", NULL, MTX_DEF | MTX_RECURSE);

	/* initialize packet queues */
	NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN);
	NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN);
	NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN);

	/* initialize glue task */
	TASK_INIT(&sc->sc_task, 0, ubt_task, sc);

	/*
	 * Configure Bluetooth USB device. Discover all required USB
	 * interfaces and endpoints.
	 *
	 * USB device must present two interfaces:
	 * 1) Interface 0 that has 3 endpoints
	 *	1) Interrupt endpoint to receive HCI events
	 *	2) Bulk IN endpoint to receive ACL data
	 *	3) Bulk OUT endpoint to send ACL data
	 *
	 * 2) Interface 1 then has 2 endpoints
	 *	1) Isochronous IN endpoint to receive SCO data
 	 *	2) Isochronous OUT endpoint to send SCO data
	 *
	 * Interface 1 (with isochronous endpoints) has several alternate
	 * configurations with different packet size.
	 */

	/*
	 * For interface #1 search alternate settings, and find
	 * the descriptor with the largest wMaxPacketSize
	 */

	wMaxPacketSize = 0;
	alt_index = 0;
	i = 0;
	j = 0;
	ed = NULL;

	/* 
	 * Search through all the descriptors looking for the largest
	 * packet size:
	 */
	while ((ed = (struct usb_endpoint_descriptor *)usb_desc_foreach(
	    usbd_get_config_descriptor(uaa->device), 
	    (struct usb_descriptor *)ed))) {

		if ((ed->bDescriptorType == UDESC_INTERFACE) &&
		    (ed->bLength >= sizeof(*id))) {
			id = (struct usb_interface_descriptor *)ed;
			i = id->bInterfaceNumber;
			j = id->bAlternateSetting;
		}

		if ((ed->bDescriptorType == UDESC_ENDPOINT) &&
		    (ed->bLength >= sizeof(*ed)) &&
		    (i == 1)) {
			uint16_t temp;

			temp = UGETW(ed->wMaxPacketSize);
			if (temp > wMaxPacketSize) {
				wMaxPacketSize = temp;
				alt_index = j;
			}
		}
	}

	/* Set alt configuration on interface #1 only if we found it */
	if (wMaxPacketSize > 0 &&
	    usbd_set_alt_interface_index(uaa->device, 1, alt_index)) {
		UBT_ALERT(sc, "could not set alternate setting %d " \
			"for interface 1!\n", alt_index);
		goto detach;
	}

	/* Setup transfers for both interfaces */
	if (usbd_transfer_setup(uaa->device, iface_index, sc->sc_xfer,
			ubt_config, UBT_N_TRANSFER, sc, &sc->sc_if_mtx)) {
		UBT_ALERT(sc, "could not allocate transfers\n");
		goto detach;
	}

	/* Claim all interfaces belonging to the Bluetooth part */
	for (i = 1;; i++) {
		iface = usbd_get_iface(uaa->device, i);
		if (iface == NULL)
			break;
		id = usbd_get_interface_descriptor(iface);

		if ((id != NULL) &&
		    (id->bInterfaceClass == UICLASS_WIRELESS) &&
		    (id->bInterfaceSubClass == UISUBCLASS_RF) &&
		    (id->bInterfaceProtocol == UIPROTO_BLUETOOTH)) {
			usbd_set_parent_iface(uaa->device, i,
			    uaa->info.bIfaceIndex);
		}
	}
	return (0); /* success */

detach:
	ubt_detach(dev);

	return (ENXIO);
} /* ubt_attach */
示例#23
0
Static int
uftdi_param(void *vsc, int portno, struct termios *t)
{
	struct uftdi_softc *sc = vsc;
	usb_device_request_t req;
	usbd_status err;
	int rate, data, flow;

	DPRINTF(("uftdi_param: sc=%p\n", sc));

	if (sc->sc_dying)
		return (EIO);

	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
	req.bRequest = FTDI_SIO_SET_BITMODE;
	USETW(req.wValue, FTDI_BITMODE_RESET << 8 | 0x00);
	USETW(req.wIndex, portno);
	USETW(req.wLength, 0);
	err = usbd_do_request(sc->sc_udev, &req, NULL);
	if (err)
		return (EIO);

	switch (sc->sc_type) {
	case UFTDI_TYPE_SIO:
		switch (t->c_ospeed) {
		case 300: rate = ftdi_sio_b300; break;
		case 600: rate = ftdi_sio_b600; break;
		case 1200: rate = ftdi_sio_b1200; break;
		case 2400: rate = ftdi_sio_b2400; break;
		case 4800: rate = ftdi_sio_b4800; break;
		case 9600: rate = ftdi_sio_b9600; break;
		case 19200: rate = ftdi_sio_b19200; break;
		case 38400: rate = ftdi_sio_b38400; break;
		case 57600: rate = ftdi_sio_b57600; break;
		case 115200: rate = ftdi_sio_b115200; break;
		default:
			return (EINVAL);
		}
		break;

	case UFTDI_TYPE_8U232AM:
		switch(t->c_ospeed) {
		case 300: rate = ftdi_8u232am_b300; break;
		case 600: rate = ftdi_8u232am_b600; break;
		case 1200: rate = ftdi_8u232am_b1200; break;
		case 2400: rate = ftdi_8u232am_b2400; break;
		case 4800: rate = ftdi_8u232am_b4800; break;
		case 9600: rate = ftdi_8u232am_b9600; break;
		case 19200: rate = ftdi_8u232am_b19200; break;
		case 38400: rate = ftdi_8u232am_b38400; break;
		case 57600: rate = ftdi_8u232am_b57600; break;
		case 115200: rate = ftdi_8u232am_b115200; break;
		case 230400: rate = ftdi_8u232am_b230400; break;
		case 460800: rate = ftdi_8u232am_b460800; break;
		case 921600: rate = ftdi_8u232am_b921600; break;
		default:
			return (EINVAL);
		}
		break;

	default:
		return (EINVAL);
	}
	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
	req.bRequest = FTDI_SIO_SET_BAUD_RATE;
	USETW(req.wValue, rate);
	USETW(req.wIndex, portno);
	USETW(req.wLength, 0);
	DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x "
		    "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest,
		    UGETW(req.wValue), UGETW(req.wIndex), UGETW(req.wLength)));
	err = usbd_do_request(sc->sc_udev, &req, NULL);
	if (err)
		return (EIO);

	if (ISSET(t->c_cflag, CSTOPB))
		data = FTDI_SIO_SET_DATA_STOP_BITS_2;
	else
		data = FTDI_SIO_SET_DATA_STOP_BITS_1;
	if (ISSET(t->c_cflag, PARENB)) {
		if (ISSET(t->c_cflag, PARODD))
			data |= FTDI_SIO_SET_DATA_PARITY_ODD;
		else
			data |= FTDI_SIO_SET_DATA_PARITY_EVEN;
	} else
		data |= FTDI_SIO_SET_DATA_PARITY_NONE;
	switch (ISSET(t->c_cflag, CSIZE)) {
	case CS5:
		data |= FTDI_SIO_SET_DATA_BITS(5);
		break;
	case CS6:
		data |= FTDI_SIO_SET_DATA_BITS(6);
		break;
	case CS7:
		data |= FTDI_SIO_SET_DATA_BITS(7);
		break;
	case CS8:
		data |= FTDI_SIO_SET_DATA_BITS(8);
		break;
	}
	sc->last_lcr = data;

	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
	req.bRequest = FTDI_SIO_SET_DATA;
	USETW(req.wValue, data);
	USETW(req.wIndex, portno);
	USETW(req.wLength, 0);
	DPRINTFN(2,("uftdi_param: reqtype=0x%02x req=0x%02x value=0x%04x "
		    "index=0x%04x len=%d\n", req.bmRequestType, req.bRequest,
		    UGETW(req.wValue), UGETW(req.wIndex), UGETW(req.wLength)));
	err = usbd_do_request(sc->sc_udev, &req, NULL);
	if (err)
		return (EIO);

	if (ISSET(t->c_cflag, CRTSCTS)) {
		flow = FTDI_SIO_RTS_CTS_HS;
		USETW(req.wValue, 0);
	} else if (ISSET(t->c_iflag, IXON) && ISSET(t->c_iflag, IXOFF)) {
		flow = FTDI_SIO_XON_XOFF_HS;
		USETW2(req.wValue, t->c_cc[VSTOP], t->c_cc[VSTART]);
	} else {
		flow = FTDI_SIO_DISABLE_FLOW_CTRL;
		USETW(req.wValue, 0);
	}
	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
	req.bRequest = FTDI_SIO_SET_FLOW_CTRL;
	USETW2(req.wIndex, flow, portno);
	USETW(req.wLength, 0);
	err = usbd_do_request(sc->sc_udev, &req, NULL);
	if (err)
		return (EIO);

	return (0);
}
示例#24
0
文件: ng_ubt.c 项目: 2asoft/freebsd
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 */
示例#25
0
void
uhub_attach(struct device *parent, struct device *self, void *aux)
{
	struct uhub_softc *sc = (struct uhub_softc *)self;
	struct usb_attach_arg *uaa = aux;
	struct usbd_device *dev = uaa->device;
	struct usbd_hub *hub = NULL;
	union {
		usb_hub_descriptor_t	hs;
		usb_hub_ss_descriptor_t	ss;
	} hd;
	int p, port, nports, powerdelay;
	struct usbd_interface *iface;
	usb_endpoint_descriptor_t *ed;
	struct usbd_tt *tts = NULL;
	uint8_t ttthink = 0;
	usbd_status err;
#ifdef UHUB_DEBUG
	int nremov;
#endif

	sc->sc_hub = dev;

	err = usbd_set_config_index(dev, 0, 1);
	if (err) {
		DPRINTF("%s: configuration failed, error=%s\n",
			 sc->sc_dev.dv_xname, usbd_errstr(err));
		return;
	}

	if (dev->depth > USB_HUB_MAX_DEPTH) {
		printf("%s: hub depth (%d) exceeded, hub ignored\n",
		       sc->sc_dev.dv_xname, USB_HUB_MAX_DEPTH);
		return;
	}

	/*
	 * Super-Speed hubs need to know their depth to be able to
	 * parse the bits of the route-string that correspond to
	 * their downstream port number.
	 *
	 * This does no apply to root hubs.
	 */
	if (dev->depth != 0 && dev->speed == USB_SPEED_SUPER) {
		if (usbd_set_hub_depth(dev, dev->depth - 1)) {
			printf("%s: unable to set HUB depth\n",
			    sc->sc_dev.dv_xname);
			return;
		}
	}

	/* Get hub descriptor. */
	if (dev->speed == USB_SPEED_SUPER) {
		err = usbd_get_hub_ss_descriptor(dev, &hd.ss, 1);
		nports = hd.ss.bNbrPorts;
		powerdelay = (hd.ss.bPwrOn2PwrGood * UHD_PWRON_FACTOR);
		if (!err && nports > 7)
			usbd_get_hub_ss_descriptor(dev, &hd.ss, nports);
	} else {
		err = usbd_get_hub_descriptor(dev, &hd.hs, 1);
		nports = hd.hs.bNbrPorts;
		powerdelay = (hd.hs.bPwrOn2PwrGood * UHD_PWRON_FACTOR);
		ttthink = UGETW(hd.hs.wHubCharacteristics) & UHD_TT_THINK;
		if (!err && nports > 7)
			usbd_get_hub_descriptor(dev, &hd.hs, nports);
	}

	if (err) {
		DPRINTF("%s: getting hub descriptor failed, error=%s\n",
			 sc->sc_dev.dv_xname, usbd_errstr(err));
		return;
	}

#ifdef UHUB_DEBUG
	for (nremov = 0, port = 1; port <= nports; port++) {
		if (dev->speed == USB_SPEED_SUPER) {
			if (!UHD_NOT_REMOV(&hd.ss, port))
				nremov++;
		} else {
			if (!UHD_NOT_REMOV(&hd.hs, port))
				nremov++;
		}
	}

	printf("%s: %d port%s with %d removable, %s powered",
	       sc->sc_dev.dv_xname, nports, nports != 1 ? "s" : "",
	       nremov, dev->self_powered ? "self" : "bus");

	if (dev->depth > 0 && UHUB_IS_HIGH_SPEED(sc)) {
		printf(", %s transaction translator%s",
		    UHUB_IS_SINGLE_TT(sc) ? "single" : "multiple",
		    UHUB_IS_SINGLE_TT(sc) ? "" : "s");
	}

	printf("\n");
#endif

	if (nports == 0) {
		printf("%s: no ports, hub ignored\n", sc->sc_dev.dv_xname);
		goto bad;
	}

	hub = malloc(sizeof(*hub), M_USBDEV, M_NOWAIT);
	if (hub == NULL)
		return;
	hub->ports = mallocarray(nports, sizeof(struct usbd_port),
	    M_USBDEV, M_NOWAIT);
	if (hub->ports == NULL) {
		free(hub, M_USBDEV, 0);
		return;
	}
	dev->hub = hub;
	dev->hub->hubsoftc = sc;
	hub->explore = uhub_explore;
	hub->nports = nports;
	hub->powerdelay = powerdelay;
	hub->ttthink = ttthink >> 5;

	if (!dev->self_powered && dev->powersrc->parent != NULL &&
	    !dev->powersrc->parent->self_powered) {
		printf("%s: bus powered hub connected to bus powered hub, "
		       "ignored\n", sc->sc_dev.dv_xname);
		goto bad;
	}

	/* Set up interrupt pipe. */
	err = usbd_device2interface_handle(dev, 0, &iface);
	if (err) {
		printf("%s: no interface handle\n", sc->sc_dev.dv_xname);
		goto bad;
	}
	ed = usbd_interface2endpoint_descriptor(iface, 0);
	if (ed == NULL) {
		printf("%s: no endpoint descriptor\n", sc->sc_dev.dv_xname);
		goto bad;
	}
	if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
		printf("%s: bad interrupt endpoint\n", sc->sc_dev.dv_xname);
		goto bad;
	}

	sc->sc_statuslen = (nports + 1 + 7) / 8;
	sc->sc_statusbuf = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
	if (!sc->sc_statusbuf)
		goto bad;

	err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
		  USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_statusbuf,
		  sc->sc_statuslen, uhub_intr, UHUB_INTR_INTERVAL);
	if (err) {
		printf("%s: cannot open interrupt pipe\n",
		       sc->sc_dev.dv_xname);
		goto bad;
	}

	/* Wait with power off for a while. */
	usbd_delay_ms(dev, USB_POWER_DOWN_TIME);

	/*
	 * To have the best chance of success we do things in the exact same
	 * order as Windoze98.  This should not be necessary, but some
	 * devices do not follow the USB specs to the letter.
	 *
	 * These are the events on the bus when a hub is attached:
	 *  Get device and config descriptors (see attach code)
	 *  Get hub descriptor (see above)
	 *  For all ports
	 *     turn on power
	 *     wait for power to become stable
	 * (all below happens in explore code)
	 *  For all ports
	 *     clear C_PORT_CONNECTION
	 *  For all ports
	 *     get port status
	 *     if device connected
	 *        wait 100 ms
	 *        turn on reset
	 *        wait
	 *        clear C_PORT_RESET
	 *        get port status
	 *        proceed with device attachment
	 */

	if (UHUB_IS_HIGH_SPEED(sc)) {
		tts = mallocarray((UHUB_IS_SINGLE_TT(sc) ? 1 : nports),
		    sizeof (struct usbd_tt), M_USBDEV, M_NOWAIT);
		if (!tts)
			goto bad;
	}
	/* Set up data structures */
	for (p = 0; p < nports; p++) {
		struct usbd_port *up = &hub->ports[p];
		up->device = NULL;
		up->parent = dev;
		up->portno = p + 1;
		if (dev->self_powered)
			/* Self powered hub, give ports maximum current. */
			up->power = USB_MAX_POWER;
		else
			up->power = USB_MIN_POWER;
		up->restartcnt = 0;
		up->reattach = 0;
		if (UHUB_IS_HIGH_SPEED(sc)) {
			up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
			up->tt->hub = hub;
		} else {
			up->tt = NULL;
		}
	}

	for (port = 1; port <= nports; port++) {
		/* Turn the power on. */
		err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
		if (err)
			printf("%s: port %d power on failed, %s\n",
			       sc->sc_dev.dv_xname, port,
			       usbd_errstr(err));
		/* Make sure we check the port status at least once. */
		sc->sc_status |= (1 << port);
	}

	/* Wait for stable power. */
        if (dev->powersrc->parent != NULL)
		usbd_delay_ms(dev, powerdelay + USB_EXTRA_POWER_UP_TIME);

	/* The usual exploration will finish the setup. */

	sc->sc_running = 1;

	return;

 bad:
	if (sc->sc_statusbuf)
		free(sc->sc_statusbuf, M_USBDEV, 0);
	if (hub) {
		if (hub->ports)
			free(hub->ports, M_USBDEV, 0);
		free(hub, M_USBDEV, 0);
	}
	dev->hub = NULL;
}
示例#26
0
void 
ubsa_attach(device_t parent, device_t self, void *aux)
{
	struct ubsa_softc *sc = device_private(self);
	struct usb_attach_arg *uaa = aux;
	usbd_device_handle dev = uaa->device;
	usb_config_descriptor_t *cdesc;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	char *devinfop;
	usbd_status err;
	struct ucom_attach_args uca;
	int i;

	sc->sc_dev = self;

	aprint_naive("\n");
	aprint_normal("\n");

	devinfop = usbd_devinfo_alloc(dev, 0);
	aprint_normal_dev(self, "%s\n", devinfop);
	usbd_devinfo_free(devinfop);

        sc->sc_udev = dev;
	sc->sc_config_index = UBSA_DEFAULT_CONFIG_INDEX;
	sc->sc_numif = 1; /* default device has one interface */

	/*
	 * initialize rts, dtr variables to something
	 * different from boolean 0, 1
	 */
	sc->sc_dtr = -1;
	sc->sc_rts = -1;

	/*
	 * Quad UMTS cards use different requests to
	 * control com settings and only some.
	 */
	sc->sc_quadumts = 0;
	if (uaa->vendor == USB_VENDOR_OPTIONNV) {
		switch (uaa->product) {
		case USB_PRODUCT_OPTIONNV_QUADUMTS:
		case USB_PRODUCT_OPTIONNV_QUADUMTS2:
			sc->sc_quadumts = 1;
			break;
		}
	}

	DPRINTF(("ubsa attach: sc = %p\n", sc));

	/* Move the device into the configured state. */
	err = usbd_set_config_index(dev, sc->sc_config_index, 1);
	if (err) {
		aprint_error_dev(self,
		    "failed to set configuration: %s\n",
		    usbd_errstr(err));
		sc->sc_dying = 1;
		goto error;
	}

	/* get the config descriptor */
	cdesc = usbd_get_config_descriptor(sc->sc_udev);

	if (cdesc == NULL) {
		aprint_error_dev(self,
		    "failed to get configuration descriptor\n");
		sc->sc_dying = 1;
		goto error;
	}

	sc->sc_intr_number = -1;
	sc->sc_intr_pipe = NULL;

	/* get the interfaces */
	err = usbd_device2interface_handle(dev, UBSA_IFACE_INDEX_OFFSET,
			 &sc->sc_iface[0]);
	if (err) {
		/* can not get main interface */
		sc->sc_dying = 1;
		goto error;
	}

	/* Find the endpoints */
	id = usbd_get_interface_descriptor(sc->sc_iface[0]);
	sc->sc_iface_number[0] = id->bInterfaceNumber;

	/* initialize endpoints */
	uca.bulkin = uca.bulkout = -1;

	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_iface[0], i);
		if (ed == NULL) {
			aprint_error_dev(self,
			     "no endpoint descriptor for %d\n", i);
			break;
		}

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
			sc->sc_intr_number = ed->bEndpointAddress;
			sc->sc_isize = UGETW(ed->wMaxPacketSize);
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			uca.bulkin = ed->bEndpointAddress;
			uca.ibufsize = UGETW(ed->wMaxPacketSize);
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
			uca.bulkout = ed->bEndpointAddress;
			uca.obufsize = UGETW(ed->wMaxPacketSize);
		}
	} /* end of Endpoint loop */

	if (sc->sc_intr_number == -1) {
		aprint_error_dev(self, "Could not find interrupt in\n");
		sc->sc_dying = 1;
		goto error;
	}

	if (uca.bulkin == -1) {
		aprint_error_dev(self, "Could not find data bulk in\n");
		sc->sc_dying = 1;
		goto error;
	}

	if (uca.bulkout == -1) {
		aprint_error_dev(self, "Could not find data bulk out\n");
		sc->sc_dying = 1;
		goto error;
	}

	uca.portno = 0;
	/* bulkin, bulkout set above */
	uca.ibufsizepad = uca.ibufsize;
	uca.opkthdrlen = 0;
	uca.device = dev;
	uca.iface = sc->sc_iface[0];
	uca.methods = &ubsa_methods;
	uca.arg = sc;
	uca.info = NULL;
	DPRINTF(("ubsa: int#=%d, in = 0x%x, out = 0x%x, intr = 0x%x\n",
    		i, uca.bulkin, uca.bulkout, sc->sc_intr_number));
	sc->sc_subdevs[0] = config_found_sm_loc(self, "ucombus", NULL, &uca,
				    ucomprint, ucomsubmatch);

	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev,
			   sc->sc_dev);

	return;

error:
	return;
}
示例#27
0
int
uhub_port_connect(struct uhub_softc *sc, int port, int status, int change)
{
	struct usbd_port *up = &sc->sc_hub->hub->ports[port-1];
	int speed;

	/* We have a connect status change, handle it. */
	usbd_clear_port_feature(sc->sc_hub, port, UHF_C_PORT_CONNECTION);

	/*
	 * If there is already a device on the port the change status
	 * must mean that is has disconnected.  Looking at the
	 * current connect status is not enough to figure this out
	 * since a new unit may have been connected before we handle
	 * the disconnect.
	 */
	if (up->device != NULL) {
		/* Disconnected */
		usbd_detach(up->device, &sc->sc_dev);
		up->device = NULL;
	}

	/* Nothing connected, just ignore it. */
	if ((status & UPS_CURRENT_CONNECT_STATUS) == 0)
		return (0);

	/* Connected */
	if ((status & (UPS_PORT_POWER|UPS_PORT_POWER_SS)) == 0) {
		printf("%s: connected port %d has no power\n", DEVNAME(sc),
		    port);
		return (-1);
	}

	/* Wait for maximum device power up time. */
	usbd_delay_ms(sc->sc_hub, USB_PORT_POWERUP_DELAY);

	/* Reset port, which implies enabling it. */
	if (usbd_reset_port(sc->sc_hub, port)) {
		printf("%s: port %d reset failed\n", DEVNAME(sc), port);
		return (-1);
	}
	/* Get port status again, it might have changed during reset */
	if (usbd_get_port_status(sc->sc_hub, port, &up->status))
		return (-1);

	status = UGETW(up->status.wPortStatus);
	change = UGETW(up->status.wPortChange);
	DPRINTF("%s: port %d status=0x%04x change=0x%04x\n", DEVNAME(sc),
	    port, status, change);

	/* Nothing connected, just ignore it. */
	if ((status & UPS_CURRENT_CONNECT_STATUS) == 0) {
		DPRINTF("%s: port %d, device disappeared after reset\n",
		    DEVNAME(sc), port);
		return (-1);
	}

	/*
	 * Figure out device speed.  This is a bit tricky because
	 * UPS_PORT_POWER_SS and UPS_LOW_SPEED share the same bit.
	 */
	if ((status & UPS_PORT_POWER) == 0)
		status &= ~UPS_PORT_POWER_SS;

	if (status & UPS_HIGH_SPEED)
		speed = USB_SPEED_HIGH;
	else if (status & UPS_LOW_SPEED)
		speed = USB_SPEED_LOW;
	else {
		/*
		 * If there is no power bit set, it is certainly
		 * a Super Speed device, so use the speed of its
		 * parent hub.
		 */
		if (status & UPS_PORT_POWER)
			speed = USB_SPEED_FULL;
		else
			speed = sc->sc_hub->speed;
	}

	/*
	 * Reduce the speed, otherwise we won't setup the proper
	 * transfer methods.
	 */
	if (speed > sc->sc_hub->speed)
		speed = sc->sc_hub->speed;

	/* Get device info and set its address. */
	if (usbd_new_device(&sc->sc_dev, sc->sc_hub->bus, sc->sc_hub->depth + 1,
	    speed, port, up)) {
		/*
		 * The unit refused to accept a new address, or had
		 * some other serious problem.  Since we cannot leave
		 * at 0 we have to disable the port instead.
		 */
		printf("%s: device problem, disabling port %d\n", DEVNAME(sc),
		    port);
		usbd_clear_port_feature(sc->sc_hub, port, UHF_PORT_ENABLE);

		return (-1);
	}

	return (0);
}
示例#28
0
void
umsm_attach(struct device *parent, struct device *self, void *aux)
{
	struct umsm_softc *sc = (struct umsm_softc *)self;
	struct usb_attach_arg *uaa = aux;
	struct ucom_attach_args uca;
	usb_interface_descriptor_t *id;
	usb_endpoint_descriptor_t *ed;
	int i;

	bzero(&uca, sizeof(uca));
	sc->sc_udev = uaa->device;
	sc->sc_iface = uaa->iface;
	sc->sc_flag  = umsm_lookup(uaa->vendor, uaa->product)->umsm_flag;

	id = usbd_get_interface_descriptor(sc->sc_iface);

	/*
	 * Some 3G modems have multiple interfaces and some of them
	 * are umass class. Don't claim ownership in such case.
	 */
	if (id == NULL || id->bInterfaceClass == UICLASS_MASS) {
		/*
		 * Some 3G modems require a special request to
		 * enable their modem function.
		 */
		if ((sc->sc_flag & DEV_HUAWEI) && uaa->ifaceno == 0) {
                        umsm_huawei_changemode(uaa->device);
			printf("%s: umass only mode. need to reattach\n",
				sc->sc_dev.dv_xname);
		} else if ((sc->sc_flag & DEV_TRUINSTALL) &&
			    uaa->ifaceno == 0) {
			umsm_truinstall_changemode(uaa->device);
			printf("%s: truinstall mode. need to reattach\n",
				sc->sc_dev.dv_xname);
		} else if ((sc->sc_flag & DEV_UMASS) && uaa->ifaceno == 0) {
			umsm_umass_changemode(sc);
		}

		/*
		 * The device will reset its own bus from the device side
		 * when its mode was changed, so just return.
		 */
		return;
	}

	sc->sc_iface_no = id->bInterfaceNumber;
	uca.bulkin = uca.bulkout = -1;
	sc->sc_intr_number = sc->sc_isize = -1;
	for (i = 0; i < id->bNumEndpoints; i++) {
		ed = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
		if (ed == NULL) {
			printf("%s: no endpoint descriptor found for %d\n",
			    sc->sc_dev.dv_xname, i);
			usbd_deactivate(sc->sc_udev);
			return;
		}

		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
			sc->sc_intr_number = ed->bEndpointAddress;
			sc->sc_isize = UGETW(ed->wMaxPacketSize);
			DPRINTF(("%s: find interrupt endpoint for %s\n",
				__func__, sc->sc_dev.dv_xname));
		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
			uca.bulkin = ed->bEndpointAddress;
		else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
			uca.bulkout = ed->bEndpointAddress;
	}
	if (uca.bulkin == -1 || uca.bulkout == -1) {
		printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
		usbd_deactivate(sc->sc_udev);
		return;
	}

	sc->sc_dtr = sc->sc_rts = -1;

	/* We need to force size as some devices lie */
	uca.ibufsize = UMSMBUFSZ;
	uca.obufsize = UMSMBUFSZ;
	uca.ibufsizepad = UMSMBUFSZ;
	uca.opkthdrlen = 0;
	uca.device = sc->sc_udev;
	uca.iface = sc->sc_iface;
	uca.methods = &umsm_methods;
	uca.arg = sc;
	uca.info = NULL;
	uca.portno = UCOM_UNK_PORTNO;

	sc->sc_subdev = config_found_sm(self, &uca, ucomprint, ucomsubmatch);
}
示例#29
0
static usbd_status
alloc_all_endpoints_yamaha(struct umidi_softc *sc)
{
	/* This driver currently supports max 1in/1out bulk endpoints */
	usb_descriptor_t *desc;
	umidi_cs_descriptor_t *udesc;
	usb_endpoint_descriptor_t *epd;
	int out_addr, in_addr, i;
	int dir;
	size_t remain, descsize;

	sc->sc_out_num_jacks = sc->sc_in_num_jacks = 0;
	out_addr = in_addr = 0;

	/* detect endpoints */
	desc = TO_D(usbd_get_interface_descriptor(sc->sc_iface));
	for (i=(int)TO_IFD(desc)->bNumEndpoints-1; i>=0; i--) {
		epd = usbd_interface2endpoint_descriptor(sc->sc_iface, i);
		KASSERT(epd != NULL);
		if (UE_GET_XFERTYPE(epd->bmAttributes) == UE_BULK) {
			dir = UE_GET_DIR(epd->bEndpointAddress);
			if (dir==UE_DIR_OUT && !out_addr)
				out_addr = epd->bEndpointAddress;
			else if (dir==UE_DIR_IN && !in_addr)
				in_addr = epd->bEndpointAddress;
		}
	}
	udesc = (umidi_cs_descriptor_t *)NEXT_D(desc);

	/* count jacks */
	if (!(udesc->bDescriptorType==UDESC_CS_INTERFACE &&
	      udesc->bDescriptorSubtype==UMIDI_MS_HEADER))
		return USBD_INVAL;
	remain = (size_t)UGETW(TO_CSIFD(udesc)->wTotalLength) -
		(size_t)udesc->bLength;
	udesc = (umidi_cs_descriptor_t *)NEXT_D(udesc);

	while (remain>=sizeof(usb_descriptor_t)) {
		descsize = udesc->bLength;
		if (descsize>remain || descsize==0)
			break;
		if (udesc->bDescriptorType==UDESC_CS_INTERFACE &&
		    remain>=UMIDI_JACK_DESCRIPTOR_SIZE) {
			if (udesc->bDescriptorSubtype==UMIDI_OUT_JACK)
				sc->sc_out_num_jacks++;
			else if (udesc->bDescriptorSubtype==UMIDI_IN_JACK)
				sc->sc_in_num_jacks++;
		}
		udesc = (umidi_cs_descriptor_t *)NEXT_D(udesc);
		remain-=descsize;
	}

	/* validate some parameters */
	if (sc->sc_out_num_jacks>UMIDI_MAX_EPJACKS)
		sc->sc_out_num_jacks = UMIDI_MAX_EPJACKS;
	if (sc->sc_in_num_jacks>UMIDI_MAX_EPJACKS)
		sc->sc_in_num_jacks = UMIDI_MAX_EPJACKS;
	if (sc->sc_out_num_jacks && out_addr) {
		sc->sc_out_num_endpoints = 1;
	} else {
		sc->sc_out_num_endpoints = 0;
		sc->sc_out_num_jacks = 0;
	}
	if (sc->sc_in_num_jacks && in_addr) {
		sc->sc_in_num_endpoints = 1;
	} else {
		sc->sc_in_num_endpoints = 0;
		sc->sc_in_num_jacks = 0;
	}
	sc->sc_endpoints = malloc(sizeof(struct umidi_endpoint)*
				  (sc->sc_out_num_endpoints+
				   sc->sc_in_num_endpoints),
				  M_USBDEV, M_WAITOK);
	if (!sc->sc_endpoints)
		return USBD_NOMEM;
	if (sc->sc_out_num_endpoints) {
		sc->sc_out_ep = sc->sc_endpoints;
		sc->sc_out_ep->sc = sc;
		sc->sc_out_ep->addr = out_addr;
		sc->sc_out_ep->num_jacks = sc->sc_out_num_jacks;
		sc->sc_out_ep->num_open = 0;
		memset(sc->sc_out_ep->jacks, 0, sizeof(sc->sc_out_ep->jacks));
	} else
		sc->sc_out_ep = NULL;

	if (sc->sc_in_num_endpoints) {
		sc->sc_in_ep = sc->sc_endpoints+sc->sc_out_num_endpoints;
		sc->sc_in_ep->sc = sc;
		sc->sc_in_ep->addr = in_addr;
		sc->sc_in_ep->num_jacks = sc->sc_in_num_jacks;
		sc->sc_in_ep->num_open = 0;
		memset(sc->sc_in_ep->jacks, 0, sizeof(sc->sc_in_ep->jacks));
	} else
		sc->sc_in_ep = NULL;

	return USBD_NORMAL_COMPLETION;
}
示例#30
0
文件: ugen.c 项目: SylvestreG/bitrig
int
ugen_do_write(struct ugen_softc *sc, int endpt, struct uio *uio, int flag)
{
	struct ugen_endpoint *sce = &sc->sc_endpoints[endpt][OUT];
	u_int32_t n;
	int flags, error = 0;
	char buf[UGEN_BBSIZE];
	struct usbd_xfer *xfer;
	usbd_status err;

	DPRINTFN(5, ("%s: ugenwrite: %d\n", sc->sc_dev.dv_xname, endpt));

	if (usbd_is_dying(sc->sc_udev))
		return (EIO);

	if (endpt == USB_CONTROL_ENDPOINT)
		return (ENODEV);

#ifdef DIAGNOSTIC
	if (sce->edesc == NULL) {
		printf("ugenwrite: no edesc\n");
		return (EIO);
	}
	if (sce->pipeh == NULL) {
		printf("ugenwrite: no pipe\n");
		return (EIO);
	}
#endif
	flags = USBD_SYNCHRONOUS;
	if (sce->timeout == 0)
		flags |= USBD_CATCH;

	switch (sce->edesc->bmAttributes & UE_XFERTYPE) {
	case UE_BULK:
		xfer = usbd_alloc_xfer(sc->sc_udev);
		if (xfer == 0)
			return (EIO);
		while ((n = min(UGEN_BBSIZE, uio->uio_resid)) != 0) {
			error = uiomove(buf, n, uio);
			if (error)
				break;
			DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
			usbd_setup_xfer(xfer, sce->pipeh, 0, buf, n,
			    flags, sce->timeout, NULL);
			err = usbd_transfer(xfer);
			if (err) {
				usbd_clear_endpoint_stall(sce->pipeh);
				if (err == USBD_INTERRUPTED)
					error = EINTR;
				else if (err == USBD_TIMEOUT)
					error = ETIMEDOUT;
				else
					error = EIO;
				break;
			}
		}
		usbd_free_xfer(xfer);
		break;
	case UE_INTERRUPT:
		xfer = usbd_alloc_xfer(sc->sc_udev);
		if (xfer == 0)
			return (EIO);
		while ((n = min(UGETW(sce->edesc->wMaxPacketSize),
		    uio->uio_resid)) != 0) {
			error = uiomove(buf, n, uio);
			if (error)
				break;
			DPRINTFN(1, ("ugenwrite: transfer %d bytes\n", n));
			usbd_setup_xfer(xfer, sce->pipeh, 0, buf, n,
			    flags, sce->timeout, NULL);
			err = usbd_transfer(xfer);
			if (err) {
				usbd_clear_endpoint_stall(sce->pipeh);
				if (err == USBD_INTERRUPTED)
					error = EINTR;
				else if (err == USBD_TIMEOUT)
					error = ETIMEDOUT;
				else
					error = EIO;
				break;
			}
		}
		usbd_free_xfer(xfer);
		break;
	default:
		return (ENXIO);
	}
	return (error);
}