⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zero.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (type == USB_DT_OTHER_SPEED_CONFIG)		hs = !hs;	if (hs)		function = is_source_sink			? hs_source_sink_function			: hs_loopback_function;	else#endif		function = is_source_sink			? fs_source_sink_function			: fs_loopback_function;	len = usb_gadget_config_buf (is_source_sink					? &source_sink_config					: &loopback_config,			buf, USB_BUFSIZ, function);	if (len < 0)		return len;	((struct usb_config_descriptor *) buf)->bDescriptorType = type;	return len;}/*-------------------------------------------------------------------------*/static struct usb_request *alloc_ep_req (struct usb_ep *ep, unsigned length){	struct usb_request	*req;	req = usb_ep_alloc_request (ep, GFP_ATOMIC);	if (req) {		req->length = length;		req->buf = usb_ep_alloc_buffer (ep, length,				&req->dma, GFP_ATOMIC);		if (!req->buf) {			usb_ep_free_request (ep, req);			req = 0;		}	}	return req;}static void free_ep_req (struct usb_ep *ep, struct usb_request *req){	if (req->buf)		usb_ep_free_buffer (ep, req->buf, req->dma, req->length);	usb_ep_free_request (ep, req);}/*-------------------------------------------------------------------------*//* optionally require specific source/sink data patterns  */static inline intcheck_read_data (	struct zero_dev		*dev,	struct usb_ep		*ep,	struct usb_request	*req){	unsigned	i;	u8		*buf = req->buf;	for (i = 0; i < req->actual; i++, buf++) {		switch (pattern) {		/* all-zeroes has no synchronization issues */		case 0:			if (*buf == 0)				continue;			break;		/* mod63 stays in sync with short-terminated transfers,		 * or otherwise when host and gadget agree on how large		 * each usb transfer request should be.  resync is done		 * with set_interface or set_config.		 */		case 1:			if (*buf == (u8)(i % 63))				continue;			break;		}		ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);		usb_ep_set_halt (ep);		return -EINVAL;	}	return 0;}static inline voidreinit_write_data (	struct zero_dev		*dev,	struct usb_ep		*ep,	struct usb_request	*req){	unsigned	i;	u8		*buf = req->buf;	switch (pattern) {	case 0:		memset (req->buf, 0, req->length);		break;	case 1:		for  (i = 0; i < req->length; i++)			*buf++ = (u8) (i % 63);		break;	}}/* if there is only one request in the queue, there'll always be an * irq delay between end of one request and start of the next. * that prevents using hardware dma queues. */static void source_sink_complete (struct usb_ep *ep, struct usb_request *req){	struct zero_dev	*dev = ep->driver_data;	int		status = req->status;	switch (status) {	case 0: 			/* normal completion? */		if (ep == dev->out_ep)			check_read_data (dev, ep, req);		else			reinit_write_data (dev, ep, req);		break;	/* this endpoint is normally active while we're configured */	case -ECONNABORTED: 		/* hardware forced ep reset */	case -ECONNRESET:		/* request dequeued */	case -ESHUTDOWN:		/* disconnect from host */		VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,				req->actual, req->length);		if (ep == dev->out_ep)			check_read_data (dev, ep, req);		free_ep_req (ep, req);		return;	case -EOVERFLOW:		/* buffer overrun on read means that					 * we didn't provide a big enough					 * buffer.					 */	default:#if 1		DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,				status, req->actual, req->length);#endif	case -EREMOTEIO:		/* short read */		break;	}	status = usb_ep_queue (ep, req, GFP_ATOMIC);	if (status) {		ERROR (dev, "kill %s:  resubmit %d bytes --> %d\n",				ep->name, req->length, status);		usb_ep_set_halt (ep);		/* FIXME recover later ... somehow */	}}static struct usb_request *source_sink_start_ep (struct usb_ep *ep, int gfp_flags){	struct usb_request	*req;	int			status;	req = alloc_ep_req (ep, buflen);	if (!req)		return 0;	memset (req->buf, 0, req->length);	req->complete = source_sink_complete;	if (strcmp (ep->name, EP_IN_NAME) == 0)		reinit_write_data (ep->driver_data, ep, req);	status = usb_ep_queue (ep, req, gfp_flags);	if (status) {		struct zero_dev	*dev = ep->driver_data;		ERROR (dev, "start %s --> %d\n", ep->name, status);		free_ep_req (ep, req);		req = 0;	}	return req;}static intset_source_sink_config (struct zero_dev *dev, int gfp_flags){	int			result = 0;	struct usb_ep		*ep;	struct usb_gadget	*gadget = dev->gadget;	gadget_for_each_ep (ep, gadget) {		const struct usb_endpoint_descriptor	*d;		/* one endpoint writes (sources) zeroes in (to the host) */		if (strcmp (ep->name, EP_IN_NAME) == 0) {			d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);			result = usb_ep_enable (ep, d);			if (result == 0) {				ep->driver_data = dev;				if (source_sink_start_ep (ep, gfp_flags) != 0) {					dev->in_ep = ep;					continue;				}				usb_ep_disable (ep);				result = -EIO;			}		/* one endpoint reads (sinks) anything out (from the host) */		} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {			d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);			result = usb_ep_enable (ep, d);			if (result == 0) {				ep->driver_data = dev;				if (source_sink_start_ep (ep, gfp_flags) != 0) {					dev->out_ep = ep;					continue;				}				usb_ep_disable (ep);				result = -EIO;			}		/* ignore any other endpoints */		} else			continue;		/* stop on error */		ERROR (dev, "can't start %s, result %d\n", ep->name, result);		break;	}	if (result == 0)		DBG (dev, "buflen %d\n", buflen);	/* caller is responsible for cleanup on error */	return result;}/*-------------------------------------------------------------------------*/static void loopback_complete (struct usb_ep *ep, struct usb_request *req){	struct zero_dev	*dev = ep->driver_data;	int		status = req->status;	switch (status) {	case 0: 			/* normal completion? */		if (ep == dev->out_ep) {			/* loop this OUT packet back IN to the host */			req->zero = (req->actual < req->length);			req->length = req->actual;			status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);			if (status == 0)				return;			/* "should never get here" */			ERROR (dev, "can't loop %s to %s: %d\n",				ep->name, dev->in_ep->name,				status);		}		/* queue the buffer for some later OUT packet */		req->length = buflen;		status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);		if (status == 0)			return;		/* "should never get here" */		/* FALLTHROUGH */	default:		ERROR (dev, "%s loop complete --> %d, %d/%d\n", ep->name,				status, req->actual, req->length);		/* FALLTHROUGH */	/* NOTE:  since this driver doesn't maintain an explicit record	 * of requests it submitted (just maintains qlen count), we	 * rely on the hardware driver to clean up on disconnect or	 * endpoint disable.	 */	case -ECONNABORTED: 		/* hardware forced ep reset */	case -ECONNRESET:		/* request dequeued */	case -ESHUTDOWN:		/* disconnect from host */		free_ep_req (ep, req);		return;	}}static intset_loopback_config (struct zero_dev *dev, int gfp_flags){	int			result = 0;	struct usb_ep		*ep;	struct usb_gadget	*gadget = dev->gadget;	gadget_for_each_ep (ep, gadget) {		const struct usb_endpoint_descriptor	*d;		/* one endpoint writes data back IN to the host */		if (strcmp (ep->name, EP_IN_NAME) == 0) {			d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);			result = usb_ep_enable (ep, d);			if (result == 0) {				ep->driver_data = dev;				dev->in_ep = ep;				continue;			}		/* one endpoint just reads OUT packets */		} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {			d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);			result = usb_ep_enable (ep, d);			if (result == 0) {				ep->driver_data = dev;				dev->out_ep = ep;				continue;			}		/* ignore any other endpoints */		} else			continue;		/* stop on error */		ERROR (dev, "can't enable %s, result %d\n", ep->name, result);		break;	}	/* allocate a bunch of read buffers and queue them all at once.	 * we buffer at most 'qlen' transfers; fewer if any need more	 * than 'buflen' bytes each.	 */	if (result == 0) {		struct usb_request	*req;		unsigned		i;		ep = dev->out_ep;		for (i = 0; i < qlen && result == 0; i++) {			req = alloc_ep_req (ep, buflen);			if (req) {				req->complete = loopback_complete;				result = usb_ep_queue (ep, req, GFP_ATOMIC);				if (result)					DBG (dev, "%s queue req --> %d\n",							ep->name, result);			} else				result = -ENOMEM;		}	}	if (result == 0)		DBG (dev, "qlen %d, buflen %d\n", qlen, buflen);	/* caller is responsible for cleanup on error */	return result;}/*-------------------------------------------------------------------------*/static void zero_reset_config (struct zero_dev *dev){	if (dev->config == 0)		return;	DBG (dev, "reset config\n");	/* just disable endpoints, forcing completion of pending i/o.	 * all our completion handlers free their requests in this case.	 */	if (dev->in_ep) {		usb_ep_disable (dev->in_ep);		dev->in_ep = 0;	}	if (dev->out_ep) {		usb_ep_disable (dev->out_ep);		dev->out_ep = 0;	}	dev->config = 0;}/* change our operational config.  this code must agree with the code * that returns config descriptors, and altsetting code. * * it's also responsible for power management interactions. some * configurations might not work with our current power sources. * * note that some device controller hardware will constrain what this * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */static intzero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags){	int			result = 0;	struct usb_gadget	*gadget = dev->gadget;	if (number == dev->config)		return 0;	if (gadget_is_sa1100 (gadget) && dev->config) {		/* tx fifo is full, but we can't clear it...*/		INFO (dev, "can't change configurations\n");		return -ESPIPE;	}	zero_reset_config (dev);	switch (number) {	case CONFIG_SOURCE_SINK:		result = set_source_sink_config (dev, gfp_flags);		break;	case CONFIG_LOOPBACK:		result = set_loopback_config (dev, gfp_flags);		break;	default:		result = -EINVAL;		/* FALL THROUGH */	case 0:		return result;	}	if (!result && (!dev->in_ep || !dev->out_ep))		result = -ENODEV;	if (result)		zero_reset_config (dev);	else {		char *speed;		switch (gadget->speed) {		case USB_SPEED_LOW:	speed = "low"; break;		case USB_SPEED_FULL:	speed = "full"; break;		case USB_SPEED_HIGH:	speed = "high"; break;		default: 		speed = "?"; break;		}

⌨️ 快捷键说明

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