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

📄 usb.c

📁 ndis在linux下的无线网卡驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  Copyright (C) 2004 Jan Kiszka *  Copyright (C) 2005 Giridhar Pemmasani * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *  GNU General Public License for more details. * */#include "ndis.h"#include "usb.h"#ifdef USB_DEBUGstatic unsigned int urb_id = 0;#define DUMP_WRAP_URB(wrap_urb, dir)					\	USBTRACE("urb %p (%d) %s: buf: %p, len: %d, pipe: 0x%x, %d",	\		 (wrap_urb)->urb, (wrap_urb)->id,			\		 (dir == USB_DIR_OUT) ? "going down" : "coming back",	\		 (wrap_urb)->urb->transfer_buffer,			\		 (wrap_urb)->urb->transfer_buffer_length,		\		 (wrap_urb)->urb->pipe, (wrap_urb)->urb->status)#define DUMP_URB_BUFFER(urb, dir)					\	while (debug >= 2) {						\		int i;							\		char msg[20], *t;					\		if (!urb->transfer_buffer)				\			break;						\		if (!((usb_pipein(urb->pipe) && dir == USB_DIR_IN) ||	\		      (usb_pipeout(urb->pipe) && dir == USB_DIR_OUT)))	\			break;						\		t = msg;						\		t += sprintf(t, "%d: ", (urb)->actual_length);		\		for (i = 0; i < urb->actual_length &&			\			     t < &msg[sizeof(msg) - 4]; i++)		\			t += sprintf(t, "%02X ",			\				     ((char *)urb->transfer_buffer)[i]); \		*t = 0;							\		USBTRACE("%s", msg);					\		break;							\	}#else#define DUMP_WRAP_URB(wrap_urb, dir) (void)0#define DUMP_URB_BUFFER(urb, dir) (void)0#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,5)#define CUR_ALT_SETTING(intf) (intf)->cur_altsetting#else#define CUR_ALT_SETTING(intf) (intf)->altsetting[(intf)->act_altsetting]#endif#ifndef USB_CTRL_SET_TIMEOUT#define USB_CTRL_SET_TIMEOUT 5000#endif#ifndef USB_CTRL_GET_TIMEOUT#define USB_CTRL_GET_TIMEOUT 5000#endif#ifndef URB_NO_TRANSFER_DMA_MAP#define URB_NO_TRANSFER_DMA_MAP 0#endif/* wrap_urb->flags *//* transfer_buffer for urb is allocated; free it in wrap_free_urb */#define WRAP_URB_COPY_BUFFER 0x01static int inline wrap_cancel_urb(struct wrap_urb *wrap_urb){	int ret;	USBTRACE("%p, %p, %d", wrap_urb, wrap_urb->urb, wrap_urb->state);	if (wrap_urb->state != URB_SUBMITTED)		USBEXIT(return -1);	ret = usb_unlink_urb(wrap_urb->urb);	USBTRACE("ret: %d", ret);	if (ret == -EINPROGRESS)		return 0;	else {		WARNING("unlink failed: %d", ret);		return ret;	}}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)#define URB_STATUS(wrap_urb) (wrap_urb->urb_status)static void *usb_buffer_alloc(struct usb_device *udev, size_t size,			      unsigned mem_flags, dma_addr_t *dma){	*dma = 0;	return kmalloc(size, mem_flags);}static void usb_buffer_free(struct usb_device *udev, size_t size, void *addr,			    dma_addr_t dma){	kfree(addr);}static void usb_init_urb(struct urb *urb){	memset(urb, 0, sizeof(*urb));}static void usb_kill_urb(struct urb *urb){	usb_unlink_urb(urb);}#else#define URB_STATUS(wrap_urb) (wrap_urb->urb->status)#endifstatic struct nt_list wrap_urb_complete_list;static NT_SPIN_LOCK wrap_urb_complete_list_lock;/* use tasklet instead of worker to process completed urbs */#define USB_TASKLET 1#ifdef USB_TASKLETstatic struct tasklet_struct wrap_urb_complete_work;static void wrap_urb_complete_worker(unsigned long dummy);#elsestatic work_struct_t wrap_urb_complete_work;static void wrap_urb_complete_worker(worker_param_t dummy);#endifstatic void kill_all_urbs(struct wrap_device *wd, int complete){	struct nt_list *ent;	struct wrap_urb *wrap_urb;	KIRQL irql;	USBENTER("%d", wd->usb.num_alloc_urbs);	while (1) {		IoAcquireCancelSpinLock(&irql);		ent = RemoveHeadList(&wd->usb.wrap_urb_list);		IoReleaseCancelSpinLock(irql);		if (!ent)			break;		wrap_urb = container_of(ent, struct wrap_urb, list);		if (wrap_urb->state == URB_SUBMITTED) {			WARNING("Windows driver %s didn't free urb: %p",				wd->driver->name, wrap_urb->urb);			if (!complete)				wrap_urb->urb->complete = NULL;			usb_kill_urb(wrap_urb->urb);		}		USBTRACE("%p, %p", wrap_urb, wrap_urb->urb);		usb_free_urb(wrap_urb->urb);		kfree(wrap_urb);	}	wd->usb.num_alloc_urbs = 0;}/* for a given Linux urb status code, return corresponding NT urb status */static USBD_STATUS wrap_urb_status(int urb_status){	switch (urb_status) {	case 0:		return USBD_STATUS_SUCCESS;	case -EPROTO:		return USBD_STATUS_BTSTUFF;	case -EILSEQ:		return USBD_STATUS_CRC;	case -EPIPE:		return USBD_STATUS_INVALID_PIPE_HANDLE;	case -ECOMM:		return USBD_STATUS_DATA_OVERRUN;	case -ENOSR:		return USBD_STATUS_DATA_UNDERRUN;	case -EOVERFLOW:		return USBD_STATUS_BABBLE_DETECTED;	case -EREMOTEIO:		return USBD_STATUS_ERROR_SHORT_TRANSFER;;	case -ENODEV:	case -ESHUTDOWN:	case -ENOENT:		return USBD_STATUS_DEVICE_GONE;	case -ENOMEM:		return USBD_STATUS_NO_MEMORY;	case -EINVAL:		return USBD_STATUS_REQUEST_FAILED;	default:		return USBD_STATUS_NOT_SUPPORTED;	}}/* for a given USBD_STATUS, return its corresponding NTSTATUS (for irp) */static NTSTATUS nt_urb_irp_status(USBD_STATUS nt_urb_status){	switch (nt_urb_status) {	case USBD_STATUS_SUCCESS:		return STATUS_SUCCESS;	case USBD_STATUS_DEVICE_GONE:		return STATUS_DEVICE_NOT_CONNECTED;	case USBD_STATUS_PENDING:		return STATUS_PENDING;	case USBD_STATUS_NOT_SUPPORTED:		return STATUS_NOT_IMPLEMENTED;	case USBD_STATUS_NO_MEMORY:		return STATUS_NO_MEMORY;	case USBD_STATUS_REQUEST_FAILED:		return STATUS_NOT_SUPPORTED;	default:		return STATUS_FAILURE;	}}static void wrap_free_urb(struct urb *urb){	struct irp *irp;	struct wrap_urb *wrap_urb;	USBTRACE("freeing urb: %p", urb);	wrap_urb = urb->context;	irp = wrap_urb->irp;	if (wrap_urb->flags & WRAP_URB_COPY_BUFFER) {		USBTRACE("freeing DMA buffer for URB: %p %p",			 urb, urb->transfer_buffer);		usb_buffer_free(IRP_WRAP_DEVICE(irp)->usb.udev,				urb->transfer_buffer_length,				urb->transfer_buffer, urb->transfer_dma);	}	if (urb->setup_packet)		kfree(urb->setup_packet);	if (IRP_WRAP_DEVICE(irp)->usb.num_alloc_urbs > MAX_ALLOCATED_URBS) {		IoAcquireCancelSpinLock(&irp->cancel_irql);		RemoveEntryList(&wrap_urb->list);		IRP_WRAP_DEVICE(irp)->usb.num_alloc_urbs--;		IoReleaseCancelSpinLock(irp->cancel_irql);		usb_free_urb(urb);		kfree(wrap_urb);	} else {		wrap_urb->state = URB_FREE;		wrap_urb->flags = 0;		wrap_urb->irp = NULL;	}	return;}void wrap_suspend_urbs(struct wrap_device *wd){	/* TODO: do we need to cancel urbs? */	USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs);}void wrap_resume_urbs(struct wrap_device *wd){	/* TODO: do we need to resubmit urbs? */	USBTRACE("%p, %d", wd, wd->usb.num_alloc_urbs);}wstdcall void wrap_cancel_irp(struct device_object *dev_obj, struct irp *irp){	struct urb *urb;	/* NB: this function is called holding Cancel spinlock */	USBENTER("irp: %p", irp);	urb = IRP_WRAP_URB(irp)->urb;	USBTRACE("canceling urb %p", urb);	if (wrap_cancel_urb(IRP_WRAP_URB(irp))) {		irp->cancel = FALSE;		ERROR("urb %p can't be canceld: %d", urb,		      IRP_WRAP_URB(irp)->state);	} else		USBTRACE("urb %p canceled", urb);	IoReleaseCancelSpinLock(irp->cancel_irql);	return;}WIN_FUNC_DECL(wrap_cancel_irp,2)static struct urb *wrap_alloc_urb(struct irp *irp, unsigned int pipe,				  void *buf, unsigned int buf_len){	struct urb *urb;	unsigned int alloc_flags;	struct wrap_urb *wrap_urb;	struct wrap_device *wd;	USBENTER("irp: %p", irp);	wd = IRP_WRAP_DEVICE(irp);	alloc_flags = gfp_irql();	IoAcquireCancelSpinLock(&irp->cancel_irql);	urb = NULL;	nt_list_for_each_entry(wrap_urb, &wd->usb.wrap_urb_list, list) {		if (cmpxchg(&wrap_urb->state, URB_FREE,			    URB_ALLOCATED) == URB_FREE) {			urb = wrap_urb->urb;			usb_init_urb(urb);			break;		}	}	if (!urb) {		IoReleaseCancelSpinLock(irp->cancel_irql);		wrap_urb = kmalloc(sizeof(*wrap_urb), alloc_flags);		if (!wrap_urb) {			WARNING("couldn't allocate memory");			return NULL;		}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)		urb = usb_alloc_urb(0, alloc_flags);#else		urb = usb_alloc_urb(0);#endif		if (!urb) {			WARNING("couldn't allocate urb");			kfree(wrap_urb);			return NULL;		}		memset(wrap_urb, 0, sizeof(*wrap_urb));		IoAcquireCancelSpinLock(&irp->cancel_irql);		wrap_urb->urb = urb;		wrap_urb->state = URB_ALLOCATED;		InsertTailList(&wd->usb.wrap_urb_list, &wrap_urb->list);		wd->usb.num_alloc_urbs++;	}#ifdef URB_ASYNC_UNLINK	urb->transfer_flags |= URB_ASYNC_UNLINK;#elif defined(USB_ASYNC_UNLINK)	urb->transfer_flags |= USB_ASYNC_UNLINK;#endif	urb->context = wrap_urb;	wrap_urb->irp = irp;	IRP_WRAP_URB(irp) = wrap_urb;	/* called as Windows function */	irp->cancel_routine = WIN_FUNC_PTR(wrap_cancel_irp,2);	IoReleaseCancelSpinLock(irp->cancel_irql);	USBTRACE("allocated urb: %p", urb);	urb->transfer_buffer_length = buf_len;	if (buf_len && buf && (!virt_addr_valid(buf)#if defined(CONFIG_HIGHMEM) || defined(CONFIG_HIGHMEM4G)			       || PageHighMem(virt_to_page(buf))#endif		    )) {		urb->transfer_buffer =			usb_buffer_alloc(wd->usb.udev, buf_len, alloc_flags,					 &urb->transfer_dma);		if (!urb->transfer_buffer) {			WARNING("couldn't allocate dma buf");			IoAcquireCancelSpinLock(&irp->cancel_irql);			wrap_urb->state = URB_FREE;			wrap_urb->irp = NULL;			IRP_WRAP_URB(irp) = NULL;			IoReleaseCancelSpinLock(irp->cancel_irql);			return NULL;		}		if (urb->transfer_dma)			urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;		wrap_urb->flags |= WRAP_URB_COPY_BUFFER;		if (usb_pipeout(pipe))			memcpy(urb->transfer_buffer, buf, buf_len);		USBTRACE("DMA buffer for urb %p is %p",			 urb, urb->transfer_buffer);	} else		urb->transfer_buffer = buf;	return urb;}static USBD_STATUS wrap_submit_urb(struct irp *irp){	int ret;	struct urb *urb;	union nt_urb *nt_urb;	urb = IRP_WRAP_URB(irp)->urb;	nt_urb = IRP_URB(irp);#ifdef USB_DEBUG	if (IRP_WRAP_URB(irp)->state != URB_ALLOCATED) {		ERROR("urb %p is in wrong state: %d",		      urb, IRP_WRAP_URB(irp)->state);		NT_URB_STATUS(nt_urb) = USBD_STATUS_REQUEST_FAILED;		return NT_URB_STATUS(nt_urb);	}	IRP_WRAP_URB(irp)->id = pre_atomic_add(urb_id, 1);#endif	DUMP_WRAP_URB(IRP_WRAP_URB(irp), USB_DIR_OUT);	irp->io_status.status = STATUS_PENDING;	irp->io_status.info = 0;	NT_URB_STATUS(nt_urb) = USBD_STATUS_PENDING;	IoMarkIrpPending(irp);	DUMP_URB_BUFFER(urb, USB_DIR_OUT);	USBTRACE("%p", urb);	IRP_WRAP_URB(irp)->state = URB_SUBMITTED;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)	ret = usb_submit_urb(urb, gfp_irql());#else	ret = usb_submit_urb(urb);#endif	if (ret) {		USBTRACE("ret: %d", ret);		wrap_free_urb(urb);		/* we assume that IRP was not in pending state before */		IoUnmarkIrpPending(irp);		NT_URB_STATUS(nt_urb) = wrap_urb_status(ret);		USBEXIT(return NT_URB_STATUS(nt_urb));	} else		USBEXIT(return USBD_STATUS_PENDING);}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)static void int_urb_unlink_complete(struct urb *urb){	struct wrap_urb *wrap_urb;	wrap_urb = urb->context;	USBTRACE("%p, %d, %d", urb, urb->status, wrap_urb->state);	if (xchg(&wrap_urb->state, URB_INT_UNLINKED) != URB_COMPLETED)		return;	urb->status = URB_STATUS(wrap_urb);	nt_spin_lock(&wrap_urb_complete_list_lock);	InsertTailList(&wrap_urb_complete_list, &wrap_urb->complete_list);	nt_spin_unlock(&wrap_urb_complete_list_lock);#ifdef USB_TASKLET	tasklet_schedule(&wrap_urb_complete_work);#else	schedule_ntos_work(&wrap_urb_complete_work);#endif}static void wrap_urb_complete(struct urb *urb)#elsestatic void wrap_urb_complete(struct urb *urb ISR_PT_REGS_PARAM_DECL)#endif{	struct irp *irp;	struct wrap_urb *wrap_urb;	wrap_urb = urb->context;	USBTRACE("%p (%p) completed", wrap_urb, urb);	irp = wrap_urb->irp;	DUMP_WRAP_URB(wrap_urb, USB_DIR_IN);	irp->cancel_routine = NULL;#ifdef USB_DEBUG	if (wrap_urb->state != URB_SUBMITTED) {		WARNING("urb %p in wrong state: %d (%d)", urb, wrap_urb->state,			urb->status);		return;	}#endif	wrap_urb->state = URB_COMPLETED;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)	URB_STATUS(wrap_urb) = urb->status;	/* prevent 2.4 kernels from resubmitting interrupt urbs;	 * completion function for unlink will process urb */	if (usb_pipeint(urb->pipe)) {		USBTRACE("%p, %d", urb, urb->status);		urb->complete = int_urb_unlink_complete;		usb_unlink_urb(urb);		return;	}#endif	nt_spin_lock(&wrap_urb_complete_list_lock);	InsertTailList(&wrap_urb_complete_list, &wrap_urb->complete_list);	nt_spin_unlock(&wrap_urb_complete_list_lock);#ifdef USB_TASKLET	tasklet_schedule(&wrap_urb_complete_work);#else	schedule_ntos_work(&wrap_urb_complete_work);#endif	USBTRACE("scheduled worker for urb %p", urb);}/* one worker for all devices */#ifdef USB_TASKLETstatic void wrap_urb_complete_worker(unsigned long dummy)

⌨️ 快捷键说明

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