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

📄 message.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * message.c - synchronous message handling */#include <linux/config.h>#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->actual_length = 0;	status = usb_submit_urb(urb, GFP_NOIO);	if (status == 0) {		if (timeout > 0) {			init_timer(&timer);			timer.expires = jiffies + msecs_to_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_dbg(&urb->dev->dev,				"%s timed out on ep%d%s len=%d/%d\n",				current->comm,				usb_pipeendpoint(urb->pipe),				usb_pipein(urb->pipe) ? "in" : "out",				urb->actual_length,				urb->transfer_buffer_length				);			if (urb->actual_length > 0)				status = 0;			else				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)static 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 msecs 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 msecs 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. * *	Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT *	ioctl, users are forced to abuse this routine by using it to submit *	URBs for interrupt endpoints.  We will take the liberty of creating *	an interrupt URB (with the default interval) if the target is an *	interrupt endpoint. */int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 			void *data, int len, int *actual_length, int timeout){	struct urb *urb;	struct usb_host_endpoint *ep;	ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out)			[usb_pipeendpoint(pipe)];	if (!ep || len < 0)		return -EINVAL;	urb = usb_alloc_urb(0, GFP_KERNEL);	if (!urb)		return -ENOMEM;	if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==			USB_ENDPOINT_XFER_INT) {		pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);		usb_fill_int_urb(urb, usb_dev, pipe, data, len,				usb_api_blocking_completion, NULL,				ep->desc.bInterval);	} else		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 != -ENODEV						&& 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,	gfp_t			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_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;	if (usb_pipein (pipe))		urb_flags |= URB_SHORT_NOT_OK;

⌨️ 快捷键说明

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