ugen.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,003 行 · 第 1/2 页

C
1,003
字号
	}	if (!sce->pipeh) {		printf("ugenwrite: no pipe\n");		return (EIO);	}#endif	DPRINTF(("ugenwrite\n"));	switch (sce->edesc->bmAttributes & UE_XFERTYPE) {	case UE_BULK:		reqh = usbd_alloc_request();		if (reqh == 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));			r = usbd_bulk_transfer(reqh, sce->pipeh, 0, buf, 					       &n, "ugenwb");			if (r != USBD_NORMAL_COMPLETION) {				if (r == USBD_INTERRUPTED)					error = EINTR;				else					error = EIO;				break;			}		}		usbd_free_request(reqh);		break;	default:		return (ENXIO);	}	return (error);}voidugenintr(reqh, addr, status)	usbd_request_handle reqh;	usbd_private_handle addr;	usbd_status status;{	struct ugen_endpoint *sce = addr;	/*struct ugen_softc *sc = sce->sc;*/	usbd_private_handle priv;	void *buffer;	u_int32_t count;	usbd_status xstatus;	u_char *ibuf;	if (status == USBD_CANCELLED)		return;	if (status != USBD_NORMAL_COMPLETION) {		DPRINTF(("ugenintr: status=%d\n", status));		usbd_clear_endpoint_stall_async(sce->pipeh);		return;	}	(void)usbd_get_request_status(reqh, &priv, &buffer, &count, &xstatus);	ibuf = sce->ibuf;	DPRINTFN(5, ("ugenintr: reqh=%p status=%d count=%d\n", 		     reqh, xstatus, count));	DPRINTFN(5, ("          data = %02x %02x %02x\n",		     ibuf[0], ibuf[1], ibuf[2]));	(void)b_to_q(ibuf, count, &sce->q);			if (sce->state & UGEN_ASLP) {		sce->state &= ~UGEN_ASLP;		DPRINTFN(5, ("ugen_intr: waking %p\n", sce));		wakeup((caddr_t)sce);	}	selwakeup(&sce->rsel);}usbd_statusugen_set_interface(sc, ifaceidx, altno)	struct ugen_softc *sc;	int ifaceidx, altno;{	usbd_interface_handle iface;	usb_endpoint_descriptor_t *ed;	usbd_status r;	struct ugen_endpoint *sce;	u_int8_t niface, nendpt, endptno, endpt;	DPRINTFN(15, ("ugen_set_interface %d %d\n", ifaceidx, altno));	r = usbd_interface_count(sc->sc_udev, &niface);	if (r != USBD_NORMAL_COMPLETION)		return (r);	if (ifaceidx < 0 || ifaceidx >= niface)		return (USBD_INVAL);		r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);	if (r != USBD_NORMAL_COMPLETION)		return (r);	r = usbd_endpoint_count(iface, &nendpt);	if (r != USBD_NORMAL_COMPLETION)		return (r);	for (endptno = 0; endptno < nendpt; endptno++) {		ed = usbd_interface2endpoint_descriptor(iface,endptno);		endpt = ed->bEndpointAddress;		sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];		sce->sc = 0;		sce->edesc = 0;		sce->iface = 0;	}	/* change setting */	r = usbd_set_interface(iface, altno);	if (r != USBD_NORMAL_COMPLETION)		return (r);	r = usbd_endpoint_count(iface, &nendpt);	if (r != USBD_NORMAL_COMPLETION)		return (r);	for (endptno = 0; endptno < nendpt; endptno++) {		ed = usbd_interface2endpoint_descriptor(iface,endptno);		endpt = ed->bEndpointAddress;		sce = &sc->sc_endpoints[UE_GET_ADDR(endpt)][UE_GET_IN(endpt)];		sce->sc = sc;		sce->edesc = ed;		sce->iface = iface;	}	return (0);}/* Retrieve a complete descriptor for a certain device and index. */usb_config_descriptor_t *ugen_get_cdesc(sc, index, lenp)	struct ugen_softc *sc;	int index;	int *lenp;{	usb_config_descriptor_t *cdesc, *tdesc, cdescr;	int len;	usbd_status r;	if (index == USB_CURRENT_CONFIG_INDEX) {		tdesc = usbd_get_config_descriptor(sc->sc_udev);		len = UGETW(tdesc->wTotalLength);		if (lenp)			*lenp = len;		cdesc = malloc(len, M_TEMP, M_WAITOK);		memcpy(cdesc, tdesc, len);		DPRINTFN(5,("ugen_get_cdesc: current, len=%d\n", len));	} else {		r = usbd_get_config_desc(sc->sc_udev, index, &cdescr);		if (r != USBD_NORMAL_COMPLETION)			return (0);		len = UGETW(cdescr.wTotalLength);		DPRINTFN(5,("ugen_get_cdesc: index=%d, len=%d\n", index, len));		if (lenp)			*lenp = len;		cdesc = malloc(len, M_TEMP, M_WAITOK);		r = usbd_get_config_desc_full(sc->sc_udev, index, cdesc, len);		if (r != USBD_NORMAL_COMPLETION) {			free(cdesc, M_TEMP);			return (0);		}	}	return (cdesc);}intugen_get_alt_index(sc, ifaceidx)	struct ugen_softc *sc;	int ifaceidx;{	usbd_interface_handle iface;	usbd_status r;	r = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);	if (r != USBD_NORMAL_COMPLETION)			return (-1);	return (usbd_get_interface_altindex(iface));}intugenioctl(dev, cmd, addr, flag, p)	dev_t dev;	u_long cmd;	caddr_t addr; 	int flag;	struct proc *p;{	USB_GET_SC(ugen, UGENUNIT(dev), sc);	int endpt = UGENENDPOINT(dev);	struct ugen_endpoint *sce;	usbd_status r;	usbd_interface_handle 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 (sc->sc_disconnected)		return (EIO);	switch (cmd) {	case FIONBIO:		/* All handled in the upper FS layer. */		return (0);	case USB_SET_SHORT_XFER:		/* This flag only affects read */		sce = &sc->sc_endpoints[endpt][IN];#ifdef DIAGNOSTIC		if (!sce->pipeh) {			printf("ugenioctl: no pipe\n");			return (EIO);		}#endif		if (*(int *)addr)			sce->state |= UGEN_SHORT_OK;		else			sce->state &= ~UGEN_SHORT_OK;		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:		r = usbd_get_config(sc->sc_udev, &conf);		if (r != USBD_NORMAL_COMPLETION)			return (EIO);		*(int *)addr = conf;		break;	case USB_SET_CONFIG:		if (!(flag & FWRITE))			return (EPERM);		r = ugen_set_config(sc, *(int *)addr);		if (r != USBD_NORMAL_COMPLETION)			return (EIO);		break;	case USB_GET_ALTINTERFACE:		ai = (struct usb_alt_interface *)addr;		r = usbd_device2interface_handle(sc->sc_udev, 						 ai->interface_index, &iface);		if (r != USBD_NORMAL_COMPLETION)			return (EINVAL);		idesc = usbd_get_interface_descriptor(iface);		if (!idesc)			return (EIO);		ai->alt_no = idesc->bAlternateSetting;		break;	case USB_SET_ALTINTERFACE:		if (!(flag & FWRITE))			return (EPERM);		ai = (struct usb_alt_interface *)addr;		r = usbd_device2interface_handle(sc->sc_udev, 						 ai->interface_index, &iface);		if (r != USBD_NORMAL_COMPLETION)			return (EINVAL);		r = ugen_set_interface(sc, ai->interface_index, ai->alt_no);		if (r != USBD_NORMAL_COMPLETION)			return (EINVAL);		break;	case USB_GET_NO_ALT:		ai = (struct usb_alt_interface *)addr;		cdesc = ugen_get_cdesc(sc, ai->config_index, 0);		if (!cdesc)			return (EINVAL);		idesc = usbd_find_idesc(cdesc, ai->interface_index, 0);		if (!idesc)			return (EINVAL);		ai->alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber);		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 = ugen_get_cdesc(sc, cd->config_index, 0);		if (!cdesc)			return (EINVAL);		cd->desc = *cdesc;		free(cdesc, M_TEMP);		break;	case USB_GET_INTERFACE_DESC:		id = (struct usb_interface_desc *)addr;		cdesc = ugen_get_cdesc(sc, id->config_index, 0);		if (!cdesc)			return (EINVAL);		if (id->config_index == USB_CURRENT_CONFIG_INDEX &&		    id->alt_index == USB_CURRENT_ALT_INDEX)			alt = ugen_get_alt_index(sc, id->interface_index);		else			alt = id->alt_index;		idesc = usbd_find_idesc(cdesc, id->interface_index, alt);		if (!idesc) {			free(cdesc, M_TEMP);			return (EINVAL);		}		id->desc = *idesc;		free(cdesc, M_TEMP);		break;	case USB_GET_ENDPOINT_DESC:		ed = (struct usb_endpoint_desc *)addr;		cdesc = ugen_get_cdesc(sc, ed->config_index, 0);		if (!cdesc)			return (EINVAL);		if (ed->config_index == USB_CURRENT_CONFIG_INDEX &&		    ed->alt_index == USB_CURRENT_ALT_INDEX)			alt = ugen_get_alt_index(sc, ed->interface_index);		else			alt = ed->alt_index;		edesc = usbd_find_edesc(cdesc, ed->interface_index, 					alt, ed->endpoint_index);		if (!edesc) {			free(cdesc, M_TEMP);			return (EINVAL);		}		ed->desc = *edesc;		free(cdesc, M_TEMP);		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 = ugen_get_cdesc(sc, fd->config_index, &len);		if (len > fd->size)			len = fd->size;		iov.iov_base = (caddr_t)fd->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((caddr_t)cdesc, len, &uio);		free(cdesc, M_TEMP);		return (error);	}	case USB_GET_STRING_DESC:		si = (struct usb_string_desc *)addr;		r = usbd_get_string_desc(sc->sc_udev, si->string_index, 					 si->language_id, &si->desc);		if (r != USBD_NORMAL_COMPLETION)			return (EINVAL);		break;	case USB_DO_REQUEST:	{		struct usb_ctl_request *ur = (void *)addr;		int len = UGETW(ur->request.wLength);		struct iovec iov;		struct uio uio;		void *ptr = 0;		usbd_status r;		int error = 0;		if (!(flag & FWRITE))			return (EPERM);		/* Avoid requests that would damage the bus integrity. */		if ((ur->request.bmRequestType == UT_WRITE_DEVICE &&		     ur->request.bRequest == UR_SET_ADDRESS) ||		    (ur->request.bmRequestType == UT_WRITE_DEVICE &&		     ur->request.bRequest == UR_SET_CONFIG) ||		    (ur->request.bmRequestType == UT_WRITE_INTERFACE &&		     ur->request.bRequest == UR_SET_INTERFACE))			return (EINVAL);		if (len < 0 || len > 32767)			return (EINVAL);		if (len != 0) {			iov.iov_base = (caddr_t)ur->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->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;			}		}		r = usbd_do_request_flags(sc->sc_udev, &ur->request, 					  ptr, ur->flags, &ur->actlen);		if (r) {			error = EIO;			goto ret;		}		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);		return (error);	}	case USB_GET_DEVICEINFO:		usbd_fill_deviceinfo(sc->sc_udev,				     (struct usb_device_info *)addr);		break;	default:		return (EINVAL);	}	return (0);}intugenpoll(dev, events, p)	dev_t dev;	int events;	struct proc *p;{	USB_GET_SC(ugen, UGENUNIT(dev), sc);	/* XXX */	struct ugen_endpoint *sce;	int revents = 0;	int s;	if (sc->sc_disconnected)		return (EIO);	sce = &sc->sc_endpoints[UGENENDPOINT(dev)][IN];#ifdef DIAGNOSTIC	if (!sce->edesc) {		printf("ugenwrite: no edesc\n");		return (EIO);	}	if (!sce->pipeh) {		printf("ugenpoll: no pipe\n");		return (EIO);	}#endif	s = splusb();	switch (sce->edesc->bmAttributes & UE_XFERTYPE) {	case UE_INTERRUPT:		if (events & (POLLIN | POLLRDNORM)) {			if (sce->q.c_cc > 0)				revents |= events & (POLLIN | POLLRDNORM);			else				selrecord(p, &sce->rsel);		}		break;	case UE_BULK:		/* 		 * We have no easy way of determining if a read will		 * yield any data or a write will happen.		 * Pretend they will.		 */		revents |= events & 			   (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM);		break;	default:		break;	}	splx(s);	return (revents);}#if defined(__FreeBSD__)static intugen_detach(device_t self){       	DPRINTF(("%s: disconnected\n", USBDEVNAME(self)));	device_set_desc(self, NULL);	return 0;}CDEV_DRIVER_MODULE(ugen, uhub, ugen_driver, ugen_devclass,			UGEN_CDEV_MAJOR, ugen_cdevsw, usbd_driver_load, 0);#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?