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

📄 message.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * message.c - synchronous message handling */#include <linux/config.h>#ifdef CONFIG_USB_DEBUG	#define DEBUG#else	#undef DEBUG#endif#include <linux/pci.h>	/* for scatterlist macros */#include <linux/usb.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/timer.h>#include <linux/ctype.h>#include <linux/device.h>#include <asm/byteorder.h>#include "hcd.h"	/* for usbcore internals */#include "usb.h"static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs){	complete((struct completion *)urb->context);}static void timeout_kill(unsigned long data){	struct urb	*urb = (struct urb *) data;	usb_unlink_urb(urb);}// Starts urb and waits for completion or timeout// note that this call is NOT interruptible, while// many device driver i/o requests should be interruptiblestatic int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length){ 	struct completion	done;	struct timer_list	timer;	int			status;	init_completion(&done); 		urb->context = &done;	urb->transfer_flags |= URB_ASYNC_UNLINK;	urb->actual_length = 0;	status = usb_submit_urb(urb, GFP_NOIO);	if (status == 0) {		if (timeout > 0) {			init_timer(&timer);			timer.expires = jiffies + timeout;			timer.data = (unsigned long)urb;			timer.function = timeout_kill;			/* grr.  timeout _should_ include submit delays. */			add_timer(&timer);		}		wait_for_completion(&done);		status = urb->status;		/* note:  HCDs return ETIMEDOUT for other reasons too */		if (status == -ECONNRESET) {			dev_warn(&urb->dev->dev,				"%s timed out on ep%d%s\n",				current->comm,				usb_pipeendpoint(urb->pipe),				usb_pipein(urb->pipe) ? "in" : "out");			status = -ETIMEDOUT;		}		if (timeout > 0)			del_timer_sync(&timer);	}	if (actual_length)		*actual_length = urb->actual_length;	usb_free_urb(urb);	return status;}/*-------------------------------------------------------------------*/// returns status (negative) or length (positive)int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, 			    struct usb_ctrlrequest *cmd,  void *data, int len, int timeout){	struct urb *urb;	int retv;	int length;	urb = usb_alloc_urb(0, GFP_NOIO);	if (!urb)		return -ENOMEM;  	usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,			     len, usb_api_blocking_completion, NULL);	retv = usb_start_wait_urb(urb, timeout, &length);	if (retv < 0)		return retv;	else		return length;}/** *	usb_control_msg - Builds a control urb, sends it off and waits for completion *	@dev: pointer to the usb device to send the message to *	@pipe: endpoint "pipe" to send the message to *	@request: USB message request value *	@requesttype: USB message request type value *	@value: USB message value *	@index: USB message index value *	@data: pointer to the data to send *	@size: length in bytes of the data to send *	@timeout: time in jiffies to wait for the message to complete before *		timing out (if 0 the wait is forever) *	Context: !in_interrupt () * *	This function sends a simple control message to a specified endpoint *	and waits for the message to complete, or timeout. *	 *	If successful, it returns the number of bytes transferred, otherwise a negative error number. * *	Don't use this function from within an interrupt context, like a *	bottom half handler.  If you need an asynchronous message, or need to send *	a message from within interrupt context, use usb_submit_urb() *      If a thread in your driver uses this call, make sure your disconnect() *      method can wait for it to complete.  Since you don't have a handle on *      the URB used, you can't cancel the request. */int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,			 __u16 value, __u16 index, void *data, __u16 size, int timeout){	struct usb_ctrlrequest *dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);	int ret;		if (!dr)		return -ENOMEM;	dr->bRequestType= requesttype;	dr->bRequest = request;	dr->wValue = cpu_to_le16p(&value);	dr->wIndex = cpu_to_le16p(&index);	dr->wLength = cpu_to_le16p(&size);	//dbg("usb_control_msg");		ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);	kfree(dr);	return ret;}/** *	usb_bulk_msg - Builds a bulk urb, sends it off and waits for completion *	@usb_dev: pointer to the usb device to send the message to *	@pipe: endpoint "pipe" to send the message to *	@data: pointer to the data to send *	@len: length in bytes of the data to send *	@actual_length: pointer to a location to put the actual length transferred in bytes *	@timeout: time in jiffies to wait for the message to complete before *		timing out (if 0 the wait is forever) *	Context: !in_interrupt () * *	This function sends a simple bulk message to a specified endpoint *	and waits for the message to complete, or timeout. *	 *	If successful, it returns 0, otherwise a negative error number. *	The number of actual bytes transferred will be stored in the  *	actual_length paramater. * *	Don't use this function from within an interrupt context, like a *	bottom half handler.  If you need an asynchronous message, or need to *	send a message from within interrupt context, use usb_submit_urb() *      If a thread in your driver uses this call, make sure your disconnect() *      method can wait for it to complete.  Since you don't have a handle on *      the URB used, you can't cancel the request. */int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 			void *data, int len, int *actual_length, int timeout){	struct urb *urb;	if (len < 0)		return -EINVAL;	urb=usb_alloc_urb(0, GFP_KERNEL);	if (!urb)		return -ENOMEM;	usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,			  usb_api_blocking_completion, NULL);	return usb_start_wait_urb(urb,timeout,actual_length);}/*-------------------------------------------------------------------*/static void sg_clean (struct usb_sg_request *io){	if (io->urbs) {		while (io->entries--)			usb_free_urb (io->urbs [io->entries]);		kfree (io->urbs);		io->urbs = NULL;	}	if (io->dev->dev.dma_mask != NULL)		usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);	io->dev = NULL;}static void sg_complete (struct urb *urb, struct pt_regs *regs){	struct usb_sg_request	*io = (struct usb_sg_request *) urb->context;	spin_lock (&io->lock);	/* In 2.5 we require hcds' endpoint queues not to progress after fault	 * reports, until the completion callback (this!) returns.  That lets	 * device driver code (like this routine) unlink queued urbs first,	 * if it needs to, since the HC won't work on them at all.  So it's	 * not possible for page N+1 to overwrite page N, and so on.	 *	 * That's only for "hard" faults; "soft" faults (unlinks) sometimes	 * complete before the HCD can get requests away from hardware,	 * though never during cleanup after a hard fault.	 */	if (io->status			&& (io->status != -ECONNRESET				|| urb->status != -ECONNRESET)			&& urb->actual_length) {		dev_err (io->dev->bus->controller,			"dev %s ep%d%s scatterlist error %d/%d\n",			io->dev->devpath,			usb_pipeendpoint (urb->pipe),			usb_pipein (urb->pipe) ? "in" : "out",			urb->status, io->status);		// BUG ();	}	if (io->status == 0 && urb->status && urb->status != -ECONNRESET) {		int		i, found, status;		io->status = urb->status;		/* the previous urbs, and this one, completed already.		 * unlink pending urbs so they won't rx/tx bad data.		 * careful: unlink can sometimes be synchronous...		 */		spin_unlock (&io->lock);		for (i = 0, found = 0; i < io->entries; i++) {			if (!io->urbs [i] || !io->urbs [i]->dev)				continue;			if (found) {				status = usb_unlink_urb (io->urbs [i]);				if (status != -EINPROGRESS && status != -EBUSY)					dev_err (&io->dev->dev,						"%s, unlink --> %d\n",						__FUNCTION__, status);			} else if (urb == io->urbs [i])				found = 1;		}		spin_lock (&io->lock);	}	urb->dev = NULL;	/* on the last completion, signal usb_sg_wait() */	io->bytes += urb->actual_length;	io->count--;	if (!io->count)		complete (&io->complete);	spin_unlock (&io->lock);}/** * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request * @io: request block being initialized.  until usb_sg_wait() returns, *	treat this as a pointer to an opaque block of memory, * @dev: the usb device that will send or receive the data * @pipe: endpoint "pipe" used to transfer the data * @period: polling rate for interrupt endpoints, in frames or * 	(for high speed endpoints) microframes; ignored for bulk * @sg: scatterlist entries * @nents: how many entries in the scatterlist * @length: how many bytes to send from the scatterlist, or zero to * 	send every byte identified in the list. * @mem_flags: SLAB_* flags affecting memory allocations in this call * * Returns zero for success, else a negative errno value.  This initializes a * scatter/gather request, allocating resources such as I/O mappings and urb * memory (except maybe memory used by USB controller drivers). * * The request must be issued using usb_sg_wait(), which waits for the I/O to * complete (or to be canceled) and then cleans up all resources allocated by * usb_sg_init(). * * The request may be canceled with usb_sg_cancel(), either before or after * usb_sg_wait() is called. */int usb_sg_init (	struct usb_sg_request	*io,	struct usb_device	*dev,	unsigned		pipe, 	unsigned		period,	struct scatterlist	*sg,	int			nents,	size_t			length,	int			mem_flags){	int			i;	int			urb_flags;	int			dma;	if (!io || !dev || !sg			|| usb_pipecontrol (pipe)			|| usb_pipeisoc (pipe)			|| nents <= 0)		return -EINVAL;	spin_lock_init (&io->lock);	io->dev = dev;	io->pipe = pipe;	io->sg = sg;	io->nents = nents;	/* not all host controllers use DMA (like the mainstream pci ones);	 * they can use PIO (sl811) or be software over another transport.	 */	dma = (dev->dev.dma_mask != NULL);	if (dma)		io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);	else		io->entries = nents;	/* initialize all the urbs we'll use */	if (io->entries <= 0)		return io->entries;	io->count = io->entries;	io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);	if (!io->urbs)		goto nomem;	urb_flags = URB_ASYNC_UNLINK | URB_NO_TRANSFER_DMA_MAP			| URB_NO_INTERRUPT;	if (usb_pipein (pipe))		urb_flags |= URB_SHORT_NOT_OK;	for (i = 0; i < io->entries; i++) {		unsigned		len;		io->urbs [i] = usb_alloc_urb (0, mem_flags);		if (!io->urbs [i]) {			io->entries = i;			goto nomem;		}		io->urbs [i]->dev = NULL;		io->urbs [i]->pipe = pipe;		io->urbs [i]->interval = period;		io->urbs [i]->transfer_flags = urb_flags;		io->urbs [i]->complete = sg_complete;		io->urbs [i]->context = io;		io->urbs [i]->status = -EINPROGRESS;		io->urbs [i]->actual_length = 0;		if (dma) {			/* hc may use _only_ transfer_dma */			io->urbs [i]->transfer_dma = sg_dma_address (sg + i);			len = sg_dma_len (sg + i);		} else {			/* hc may use _only_ transfer_buffer */			io->urbs [i]->transfer_buffer =				page_address (sg [i].page) + sg [i].offset;			len = sg [i].length;		}		if (length) {			len = min_t (unsigned, len, length);			length -= len;			if (length == 0)				io->entries = i + 1;		}		io->urbs [i]->transfer_buffer_length = len;	}	io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT;	/* transaction state */	io->status = 0;	io->bytes = 0;	init_completion (&io->complete);	return 0;nomem:	sg_clean (io);	return -ENOMEM;}/** * usb_sg_wait - synchronously execute scatter/gather request * @io: request block handle, as initialized with usb_sg_init(). * 	some fields become accessible when this call returns. * Context: !in_interrupt () * * This function blocks until the specified I/O operation completes.  It * leverages the grouping of the related I/O requests to get good transfer * rates, by queueing the requests.  At higher speeds, such queuing can * significantly improve USB throughput. * * There are three kinds of completion for this function. * (1) success, where io->status is zero.  The number of io->bytes *     transferred is as requested. * (2) error, where io->status is a negative errno value.  The number *     of io->bytes transferred before the error is usually less *     than requested, and can be nonzero. * (3) cancelation, a type of error with status -ECONNRESET that *     is initiated by usb_sg_cancel(). * * When this function returns, all memory allocated through usb_sg_init() or * this call will have been freed.  The request block parameter may still be * passed to usb_sg_cancel(), or it may be freed.  It could also be * reinitialized and then reused. * * Data Transfer Rates: * * Bulk transfers are valid for full or high speed endpoints. * The best full speed data rate is 19 packets of 64 bytes each * per frame, or 1216 bytes per millisecond. * The best high speed data rate is 13 packets of 512 bytes each * per microframe, or 52 KBytes per millisecond. * * The reason to use interrupt transfers through this API would most likely * be to reserve high speed bandwidth, where up to 24 KBytes per millisecond * could be transferred.  That capability is less useful for low or full * speed interrupt endpoints, which allow at most one packet per millisecond, * of at most 8 or 64 bytes (respectively). */void usb_sg_wait (struct usb_sg_request *io){	int		i, entries = io->entries;	/* queue the urbs.  */	spin_lock_irq (&io->lock);	for (i = 0; i < entries && !io->status; i++) {		int	retval;		io->urbs [i]->dev = io->dev;		retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC);		/* after we submit, let completions or cancelations fire;		 * we handshake using io->status.		 */		spin_unlock_irq (&io->lock);		switch (retval) {			/* maybe we retrying will recover */		case -ENXIO:	// hc didn't queue this one		case -EAGAIN:		case -ENOMEM:			io->urbs[i]->dev = NULL;			retval = 0;			i--;			yield ();			break;			/* no error? continue immediately.			 *			 * NOTE: to work better with UHCI (4K I/O buffer may			 * need 3K of TDs) it may be good to limit how many			 * URBs are queued at once; N milliseconds?			 */

⌨️ 快捷键说明

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