usbdi.c

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

C
1,320
字号
/*	$NetBSD: usbdi.c,v 1.20 1999/01/08 11:58:26 augustss Exp $	*//*	$FreeBSD: src/sys/dev/usb/usbdi.c,v 1.8.2.1 1999/05/08 23:04:58 n_hibma Exp $	*//* * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Lennart Augustsson (augustss@carlstedt.se) at * Carlstedt Research & Technology. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *        This product includes software developed by the NetBSD *        Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its *    contributors may be used to endorse or promote products derived *    from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#if defined(__NetBSD__)#include <sys/device.h>#else#include <sys/module.h>#include <sys/bus.h>#include <sys/conf.h>#endif#include <sys/malloc.h>#include <sys/proc.h>#include <dev/usb/usb.h>#include <dev/usb/usbdi.h>#include <dev/usb/usbdi_util.h>#include <dev/usb/usbdivar.h>#if defined(__FreeBSD__)#include "usb_if.h"#endif#ifdef USB_DEBUG#define DPRINTF(x)	if (usbdebug) logprintf x#define DPRINTFN(n,x)	if (usbdebug>(n)) logprintf xextern int usbdebug;#else#define DPRINTF(x)#define DPRINTFN(n,x)#endifstatic usbd_status usbd_ar_pipe  __P((usbd_pipe_handle pipe));static usbd_status usbd_ar_iface __P((usbd_interface_handle iface));static void usbd_transfer_cb __P((usbd_request_handle reqh));static void usbd_sync_transfer_cb __P((usbd_request_handle reqh));static usbd_status usbd_do_transfer __P((usbd_request_handle reqh));void usbd_do_request_async_cb 	__P((usbd_request_handle, usbd_private_handle, usbd_status));static SIMPLEQ_HEAD(, usbd_request) usbd_free_requests;#if defined(__FreeBSD__)#define USB_CDEV_MAJOR	108extern struct cdevsw usb_cdevsw;#endif#ifdef USB_DEBUGchar *usbd_error_strs[USBD_ERROR_MAX] = {	"NORMAL_COMPLETION",	"IN_PROGRESS",	"PENDING_REQUESTS",	"NOT_STARTED",	"INVAL",	"IS_IDLE",	"NOMEM",	"CANCELLED",	"BAD_ADDRESS",	"IN_USE",	"INTERFACE_NOT_ACTIVE",	"NO_ADDR",	"SET_ADDR_FAILED",	"NO_POWER",	"TOO_DEEP",	"IOERROR",	"NOT_CONFIGURED",	"TIMEOUT",	"SHORT_XFER",	"STALLED",	"XXX",};#endifusbd_status usbd_open_pipe(iface, address, flags, pipe)	usbd_interface_handle iface;	u_int8_t address;	u_int8_t flags;	usbd_pipe_handle *pipe;{ 	usbd_pipe_handle p;	struct usbd_endpoint *ep;	usbd_status r;	int i;	if (iface->state != USBD_INTERFACE_ACTIVE)		return (USBD_INTERFACE_NOT_ACTIVE);	for (i = 0; i < iface->idesc->bNumEndpoints; i++) {		ep = &iface->endpoints[i];		if (ep->edesc->bEndpointAddress == address)			goto found;	}	return (USBD_BAD_ADDRESS); found:	if ((flags & USBD_EXCLUSIVE_USE) &&	    ep->refcnt != 0)		return (USBD_IN_USE);	r = usbd_setup_pipe(iface->device, iface, ep, &p);	if (r != USBD_NORMAL_COMPLETION)		return (r);	LIST_INSERT_HEAD(&iface->pipes, p, next);	*pipe = p;	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_open_pipe_intr(iface, address, flags, pipe, priv, buffer, length, cb)	usbd_interface_handle iface;	u_int8_t address;	u_int8_t flags;	usbd_pipe_handle *pipe;	usbd_private_handle priv;	void *buffer;	u_int32_t length;	usbd_callback cb;{	usbd_status r;	usbd_request_handle reqh;	usbd_pipe_handle ipipe;	reqh = usbd_alloc_request();	if (reqh == 0)		return (USBD_NOMEM);	r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &ipipe);	if (r != USBD_NORMAL_COMPLETION)		goto bad1;	r = usbd_setup_request(reqh, ipipe, priv, buffer, length, 			       USBD_XFER_IN | flags, USBD_NO_TIMEOUT, cb);	if (r != USBD_NORMAL_COMPLETION)		goto bad2;	ipipe->intrreqh = reqh;	r = usbd_transfer(reqh);	*pipe = ipipe;	if (r != USBD_IN_PROGRESS)		goto bad3;	return (USBD_NORMAL_COMPLETION); bad3:	ipipe->intrreqh = 0; bad2:	usbd_close_pipe(ipipe); bad1:	usbd_free_request(reqh);	return r;}usbd_status usbd_open_pipe_iso(iface, address, flags, pipe, priv, bufsize, nbuf, cb)	usbd_interface_handle iface;	u_int8_t address;	u_int8_t flags;	usbd_pipe_handle *pipe;	usbd_private_handle priv;	u_int32_t bufsize;	u_int32_t nbuf;	usbd_callback cb;{	usbd_status r;	usbd_pipe_handle p;	r = usbd_open_pipe(iface, address, USBD_EXCLUSIVE_USE, &p);	if (r != USBD_NORMAL_COMPLETION)		return (r);	if (!p->methods->isobuf) {		usbd_close_pipe(p);		return (USBD_INVAL);	}	r = p->methods->isobuf(p, bufsize, nbuf);	if (r != USBD_NORMAL_COMPLETION) {		usbd_close_pipe(p);		return (r);	}		*pipe = p;	return r;}usbd_statususbd_close_pipe(pipe)	usbd_pipe_handle pipe;{	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)		return (USBD_INTERFACE_NOT_ACTIVE);	if (--pipe->refcnt != 0)		return (USBD_NORMAL_COMPLETION);	if (SIMPLEQ_FIRST(&pipe->queue) != 0)		return (USBD_PENDING_REQUESTS);	LIST_REMOVE(pipe, next);	pipe->endpoint->refcnt--;	pipe->methods->close(pipe);	if (pipe->intrreqh)		usbd_free_request(pipe->intrreqh);	free(pipe, M_USB);	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_transfer(reqh)	usbd_request_handle reqh;{	reqh->xfercb = usbd_transfer_cb;	return (usbd_do_transfer(reqh));}static usbd_statususbd_do_transfer(reqh)	usbd_request_handle reqh;{	usbd_pipe_handle pipe = reqh->pipe;	DPRINTFN(10,("usbd_do_transfer: reqh=%p\n", reqh));	reqh->done = 0;	return (pipe->methods->transfer(reqh));}usbd_request_handle usbd_alloc_request(){	usbd_request_handle reqh;	reqh = SIMPLEQ_FIRST(&usbd_free_requests);	if (reqh)#if defined(__NetBSD__)		SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, reqh, next);#elif defined(__FreeBSD__)		SIMPLEQ_REMOVE_HEAD(&usbd_free_requests, next);#endif	else		reqh = malloc(sizeof(*reqh), M_USB, M_NOWAIT);	if (!reqh)		return (0);	memset(reqh, 0, sizeof *reqh);	return (reqh);}usbd_status usbd_free_request(reqh)	usbd_request_handle reqh;{	SIMPLEQ_INSERT_HEAD(&usbd_free_requests, reqh, next);	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_setup_request(reqh, pipe, priv, buffer, length, flags, timeout, callback)	usbd_request_handle reqh;	usbd_pipe_handle pipe;	usbd_private_handle priv;	void *buffer;	u_int32_t length;	u_int16_t flags;	u_int32_t timeout;	void (*callback) __P((usbd_request_handle,			      usbd_private_handle,			      usbd_status));{	reqh->pipe = pipe;	reqh->priv = priv;	reqh->buffer = buffer;	reqh->length = length;	reqh->actlen = 0;	reqh->flags = flags;	reqh->timeout = timeout;	reqh->status = USBD_NOT_STARTED;	reqh->callback = callback;	reqh->retries = 1;	reqh->isreq = 0;	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_setup_device_request(reqh, req)	usbd_request_handle reqh;	usb_device_request_t *req;{	reqh->isreq = 1;	reqh->request = *req;	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_setup_default_request(reqh, dev, priv, timeout, req, buffer, 			   length, flags, callback)	usbd_request_handle reqh;	usbd_device_handle dev;	usbd_private_handle priv;	u_int32_t timeout;	usb_device_request_t *req;	void *buffer;	u_int32_t length;	u_int16_t flags;	void (*callback) __P((usbd_request_handle,			      usbd_private_handle,			      usbd_status));{	reqh->pipe = dev->default_pipe;	reqh->priv = priv;	reqh->buffer = buffer;	reqh->length = length;	reqh->actlen = 0;	reqh->flags = flags;	reqh->timeout = timeout;	reqh->status = USBD_NOT_STARTED;	reqh->callback = callback;	reqh->request = *req;	reqh->retries = 1;	reqh->isreq = 1;	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_set_request_timeout(reqh, timeout)	usbd_request_handle reqh;	u_int32_t timeout;{	reqh->timeout = timeout;	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_get_request_status(reqh, priv, buffer, count, status)	usbd_request_handle reqh;	usbd_private_handle *priv;	void **buffer;	u_int32_t *count;	usbd_status *status;{	*priv = reqh->priv;	*buffer = reqh->buffer;	*count = reqh->actlen;	*status = reqh->status;	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_request_device_data(reqh, req)	usbd_request_handle reqh;	usb_device_request_t *req;{	if (!reqh->isreq) 		return (USBD_INVAL);	*req = reqh->request;	return (USBD_NORMAL_COMPLETION);}#if 0usb_descriptor_t *usbd_get_descriptor(iface, desc_type)	usbd_interface_handle *iface;	u_int8_t desc_type;XX#endifusb_config_descriptor_t *usbd_get_config_descriptor(dev)	usbd_device_handle dev;{	return (dev->cdesc);}usb_interface_descriptor_t *usbd_get_interface_descriptor(iface)	usbd_interface_handle iface;{	return (iface->idesc);}usb_device_descriptor_t *usbd_get_device_descriptor(dev)	usbd_device_handle dev;{	return (&dev->ddesc);}usb_endpoint_descriptor_t *usbd_interface2endpoint_descriptor(iface, index)	usbd_interface_handle iface;	u_int8_t index;{	if (index >= iface->idesc->bNumEndpoints)		return (0);	return (iface->endpoints[index].edesc);}usbd_status usbd_set_configuration(dev, conf)	usbd_device_handle dev;	u_int8_t conf;{	return usbd_set_config_no(dev, conf, 0);}usbd_status usbd_retry_request(reqh, retry_count)	usbd_request_handle reqh;	u_int32_t retry_count;{	usbd_status r;	r = usbd_set_pipe_state(reqh->pipe, USBD_PIPE_ACTIVE);	if (r != USBD_NORMAL_COMPLETION)		return (r);	reqh->retries = retry_count;	return (usbd_transfer(reqh));}usbd_status usbd_abort_pipe(pipe)	usbd_pipe_handle pipe;{	usbd_status r;	int s, state;	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)		return (USBD_INTERFACE_NOT_ACTIVE);	s = splusb();	state = pipe->state;	r = usbd_ar_pipe(pipe);	pipe->state = state;	splx(s);	return (r);}	usbd_status usbd_abort_interface(iface)	usbd_interface_handle iface;{	usbd_status r;	int s, st;	s = splusb();	st = iface->state;	r = usbd_ar_iface(iface);	iface->state = st;	splx(s);	return (r);}usbd_status usbd_reset_pipe(pipe)	usbd_pipe_handle pipe;{	usbd_status r;	int s;	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)		return (USBD_INTERFACE_NOT_ACTIVE);	s = splusb();	r = usbd_ar_pipe(pipe);	/* XXX anything else */	pipe->state = USBD_PIPE_ACTIVE;	splx(s);	return (r);}usbd_status usbd_reset_interface(iface)	usbd_interface_handle iface;{	usbd_status r;	int s;	s = splusb();	r = usbd_ar_iface(iface);	/* XXX anything else */	iface->state = USBD_INTERFACE_ACTIVE;	splx(s);	return (r);}usbd_status usbd_clear_endpoint_stall(pipe)	usbd_pipe_handle pipe;{	usbd_device_handle dev = pipe->device;	usb_device_request_t req;	usbd_status r;	req.bmRequestType = UT_WRITE_ENDPOINT;	req.bRequest = UR_CLEAR_FEATURE;	USETW(req.wValue, UF_ENDPOINT_HALT);	USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);	USETW(req.wLength, 0);	r = usbd_do_request(dev, &req, 0);#if 0XXX should we do this?	if (r == USBD_NORMAL_COMPLETION) {		pipe->state = USBD_PIPE_ACTIVE;		/* XXX activate pipe */	}#endif	return (r);}usbd_status usbd_clear_endpoint_stall_async(pipe)	usbd_pipe_handle pipe;{	usbd_device_handle dev = pipe->device;	usb_device_request_t req;	usbd_status r;	req.bmRequestType = UT_WRITE_ENDPOINT;	req.bRequest = UR_CLEAR_FEATURE;	USETW(req.wValue, UF_ENDPOINT_HALT);	USETW(req.wIndex, pipe->endpoint->edesc->bEndpointAddress);	USETW(req.wLength, 0);	r = usbd_do_request_async(dev, &req, 0);	return (r);}usbd_status usbd_set_pipe_state(pipe, state)	usbd_pipe_handle pipe;	usbd_pipe_state state;{	int s;	usbd_status r;	usbd_request_handle reqh;	if (pipe->iface->state != USBD_INTERFACE_ACTIVE)		return (USBD_INTERFACE_NOT_ACTIVE);	if (state != USBD_PIPE_ACTIVE &&	    state != USBD_PIPE_STALLED &&	    state != USBD_PIPE_IDLE)		return (USBD_INVAL);	pipe->state = state;	r = USBD_NORMAL_COMPLETION;	if (state == USBD_PIPE_ACTIVE) {		s = splusb();		if (!pipe->running) {			reqh = SIMPLEQ_FIRST(&pipe->queue);			if (reqh != 0) {				pipe->running = 1;				splx(s);				r = pipe->methods->start(reqh);			} else				splx(s);		} else			splx(s);	}	return (r);}usbd_status usbd_get_pipe_state(pipe, state, endpoint_state, request_count)	usbd_pipe_handle pipe;	usbd_pipe_state *state;	u_int32_t *endpoint_state;	u_int32_t *request_count;{	int n;	usbd_request_handle r;	*state = pipe->state;	*endpoint_state = pipe->endpoint->state;	for (r = SIMPLEQ_FIRST(&pipe->queue), n = 0; 	     r != 0; 	     r = SIMPLEQ_NEXT(r, next), n++)		;	*request_count = n;	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_set_interface_state(iface, state)	usbd_interface_handle iface;	usbd_interface_state state;{	int ps;	usbd_pipe_handle p;	if (state == USBD_INTERFACE_ACTIVE)		ps = USBD_PIPE_ACTIVE;	else if (state == USBD_INTERFACE_STALLED)		ps = USBD_PIPE_STALLED;	else if (state == USBD_INTERFACE_IDLE)		ps = USBD_PIPE_IDLE;	else		return (USBD_INVAL);	iface->state = USBD_INTERFACE_ACTIVE; /* to allow setting the pipe */	for (p = LIST_FIRST(&iface->pipes); p != 0; p = LIST_NEXT(p, next))		usbd_set_pipe_state(p, ps);	iface->state = state;	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_get_interface_state(iface, state)	usbd_interface_handle iface;	usbd_interface_state *state;{	*state = iface->state;	return (USBD_NORMAL_COMPLETION);}usbd_status usbd_get_device_state(dev, state)	usbd_device_handle dev;	usbd_device_state *state;{	*state = dev->state;	return (USBD_NORMAL_COMPLETION);}#if 0usbd_status usbd_set_device_state(dev, state)	usbd_device_handle dev;	usbd_device_state state;X#endifusbd_status usbd_device_address(dev, address)	usbd_device_handle dev;	u_int8_t *address;{	*address = dev->address;

⌨️ 快捷键说明

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