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

📄 usb.c

📁 有关于USB的一些主机端驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
		return;
	}
	if (!(buf = malloc (256))) {
		free (envp);
		printf ("enomem2");
		return;
	}

	/* only one standardized param to hotplug command: type */
	argv [0] = hotplug_path;
	argv [1] = "usb";
	argv [2] = 0;

	/* minimal command environment */
	envp [i++] = "HOME=/";
	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";

#ifdef	DEBUG
	/* hint that policy agent should enter no-stdout debug mode */
	envp [i++] = "DEBUG=kernel";
#endif
	/* extensible set of named bus-specific parameters,
	 * supporting multiple driver selection algorithms.
	 */
	scratch = buf;

	/* action:  add, remove */
	envp [i++] = scratch;
	scratch += sprintf (scratch, "ACTION=%s", verb) + 1;

#ifdef	CONFIG_USB_DEVICEFS
	/* If this is available, userspace programs can directly read
	 * all the device descriptors we don't tell them about.  Or
	 * even act as usermode drivers.
	 *
	 * FIXME reduce hardwired intelligence here
	 */
	envp [i++] = "DEVFS=/proc/bus/usb";
	envp [i++] = scratch;
	scratch += sprintf (scratch, "DEVICE=/proc/bus/usb/%03d/%03d",
		dev->bus->busnum, dev->devnum) + 1;
#endif

	/* per-device configuration hacks are common */
	envp [i++] = scratch;
	scratch += sprintf (scratch, "PRODUCT=%x/%x/%x",
		dev->descriptor.idVendor,
		dev->descriptor.idProduct,
		dev->descriptor.bcdDevice) + 1;

	/* class-based driver binding models */
	envp [i++] = scratch;
	scratch += sprintf (scratch, "TYPE=%d/%d/%d",
			    dev->descriptor.bDeviceClass,
			    dev->descriptor.bDeviceSubClass,
			    dev->descriptor.bDeviceProtocol) + 1;
	if (dev->descriptor.bDeviceClass == 0) {
		int alt = dev->actconfig->interface [0].act_altsetting;

		/* a simple/common case: one config, one interface, one driver
		 * with current altsetting being a reasonable setting.
		 * everything needs a smart agent and usbdevfs; or can rely on
		 * device-specific binding policies.
		 */
		envp [i++] = scratch;
		scratch += sprintf (scratch, "INTERFACE=%d/%d/%d",
			dev->actconfig->interface [0].altsetting [alt].bInterfaceClass,
			dev->actconfig->interface [0].altsetting [alt].bInterfaceSubClass,
			dev->actconfig->interface [0].altsetting [alt].bInterfaceProtocol)
			+ 1;
		/* INTERFACE-0, INTERFACE-1, ... ? */
	}
	envp [i++] = 0;
	/* assert: (scratch - buf) < sizeof buf */

	/* NOTE: user mode daemons can call the agents too */

	printf ("kusbd: %s %s %d", argv [0], verb, dev->devnum);
	value = call_usermodehelper (argv [0], argv, envp);
	free (buf);
	free (envp);
	if (value != 0)
		printf ("kusbd policy returned 0x%d", value);
}

#else

static inline void
call_policy (char *verb, struct usb_device *dev)
{ } 

#endif	/* CONFIG_HOTPLUG */


/*
 * This entrypoint gets called for each new device.
 *
 * All interfaces are scanned for matching drivers.
 */
static void usb_find_drivers(struct usb_device *dev)
{
	unsigned ifnum;
	unsigned rejected = 0;
	unsigned claimed = 0;

	for (ifnum = 0; ifnum < dev->actconfig->bNumInterfaces; ifnum++) {
		/* if this interface hasn't already been claimed */
		if (!usb_interface_claimed(dev->actconfig->interface + ifnum)) {
			if (usb_find_interface_driver(dev, ifnum))
				rejected++;
			else
				claimed++;
		}
	}
 
	if (rejected)
		printf("unhandled interfaces on device\n");

	if (!claimed) {
		printf("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.\n",
			dev->devnum,
			dev->descriptor.idVendor,
			dev->descriptor.idProduct);
		printf("usb device %d(VID/PID:0x%x/0x%x) Maxpacketsize[ep0]:0x%x/iManufacture:0x%x/iProduct:0x%x/iSerialNumber:0x%x/bNumConf:0x%x.\n",
			dev->devnum,dev->descriptor.idVendor,dev->descriptor.idProduct,
			dev->descriptor.bMaxPacketSize0,
			dev->descriptor.iManufacturer,dev->descriptor.iProduct,
			dev->descriptor.iSerialNumber,dev->descriptor.bNumConfigurations);
#ifdef DEBUG
		usb_show_device(dev);
#endif
	}
}

/*
 * Only HC's should call usb_alloc_dev and usb_free_dev directly
 * Anybody may use usb_inc_dev_use or usb_dec_dev_use
 */
struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
{
	struct usb_device *dev;

	dev = (struct usb_device *)malloc(sizeof(*dev));
	if (!dev)
		return NULL;

	memset(dev, 0, sizeof(*dev));

	usb_bus_get(bus);

	dev->bus = bus;
	dev->parent = parent;
	atomic_set(&dev->refcnt, 1);
	INIT_LIST_HEAD(&dev->inodes);
	INIT_LIST_HEAD(&dev->filelist);

//	init_MUTEX(&dev->serialize);

	dev->bus->op->allocate(dev);

	return dev;
}

void usb_destroy_configuration(struct usb_device *dev)
{
	int c, i, j, k;
	
	if (!dev->config)
		return;

	if (dev->rawdescriptors) {
		for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
			free(dev->rawdescriptors[i]);

		free(dev->rawdescriptors);
	}

	for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
		struct usb_config_descriptor *cf = &dev->config[c];

		if (!cf->interface)
			break;

		for (i = 0; i < cf->bNumInterfaces; i++) {
			struct usb_interface *ifp =
				&cf->interface[i];
				
			if (!ifp->altsetting)
				break;

			for (j = 0; j < ifp->num_altsetting; j++) {
				struct usb_interface_descriptor *as =
					&ifp->altsetting[j];
					
				if(as->extra) {
					free(as->extra);
				}

				if (!as->endpoint)
					break;
					
				for(k = 0; k < as->bNumEndpoints; k++) {
					if(as->endpoint[k].extra) {
					free(as->endpoint[k].extra);
					}
				}	
				free(as->endpoint);
			}

			free(ifp->altsetting);
		}
		free(cf->interface);
	}
	free(dev->config);
}

void usb_free_dev(struct usb_device *dev)
{
	if (atomic_dec_and_test(&dev->refcnt)) {
		dev->bus->op->deallocate(dev);
		usb_destroy_configuration(dev);

		usb_bus_put(dev->bus);

		free(dev);
	}
}

void usb_inc_dev_use(struct usb_device *dev)
{
	atomic_inc(&dev->refcnt);
}

/* ------------------------------------------------------------------------------------- 
 * New USB Core Functions
 * -------------------------------------------------------------------------------------*/

/**
 *	usb_alloc_urb - creates a new urb for a USB driver to use
 *	@iso_packets: number of iso packets for this urb
 *
 *	Creates an urb for the USB driver to use and returns a pointer to it.
 *	If no memory is available, NULL is returned.
 *
 *	If the driver want to use this urb for interrupt, control, or bulk
 *	endpoints, pass '0' as the number of iso packets.
 *
 *	The driver should call usb_free_urb() when it is finished with the urb.
 */
urb_t *usb_alloc_urb(int iso_packets)
{
	urb_t *urb;

	urb = (urb_t *)malloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t));
	if (!urb) {
		err("alloc_urb: malloc failed");
		return NULL;
	}

	memset(urb, 0, sizeof(*urb));

//	spin_lock_init(&urb->lock);

	return urb;
}

/**
 *	usb_free_urb - frees the memory used by a urb
 *	@urb: pointer to the urb to free
 *
 *	If an urb is created with a call to usb_create_urb() it should be
 *	cleaned up with a call to usb_free_urb() when the driver is finished
 *	with it.
 */
void usb_free_urb(urb_t* urb)
{
	if (urb)
		free(urb);
}
/*-------------------------------------------------------------------*/
int usb_submit_urb(urb_t *urb)
{
	if (urb && urb->dev)
		return urb->dev->bus->op->submit_urb(urb);
	else
		return -ENODEV;
}

/*-------------------------------------------------------------------*/
int usb_unlink_urb(urb_t *urb)
{
	if (urb && urb->dev)
		return urb->dev->bus->op->unlink_urb(urb);
	else
		return -ENODEV;
}
/*-------------------------------------------------------------------*
 *                     COMPLETION HANDLERS                           *
 *-------------------------------------------------------------------*/

/*-------------------------------------------------------------------*
 * completion handler for compatibility wrappers (sync control/bulk) *
 *-------------------------------------------------------------------*/
static void usb_api_blocking_completion(urb_t *urb)
{
//	api_wrapper_data *awd = (api_wrapper_data *)urb->context;

//	if (waitqueue_active(awd->wakeup))
//		wake_up(awd->wakeup);
#if 0
	else
		printf("(blocking_completion): waitqueue empty!"); 
		// even occurs if urb was unlinked by timeout...
#endif
}

/*-------------------------------------------------------------------*
 *                         COMPATIBILITY STUFF                       *
 *-------------------------------------------------------------------*/

// Starts urb and waits for completion or timeout
static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
{ 
//	DECLARE_WAITQUEUE(wait, current);
//	DECLARE_WAIT_QUEUE_HEAD(wqh);
//	api_wrapper_data awd;
	int status;
	
//	urb_priv_t * urb_priv = urb->hcpriv;	//added by hcm
  
//	awd.wakeup = &wqh;
//	init_waitqueue_head(&wqh); 	
//	current->state = TASK_INTERRUPTIBLE;
//	add_wait_queue(&wqh, &wait);
//	urb->context = &awd;

	status = usb_submit_urb(urb);
	if (status) {
		// something went wrong
		usb_free_urb(urb);
//		current->state = TASK_RUNNING;
//		remove_wait_queue(&wqh, &wait);
		return status;
	}

//	printf("urb->status:%d\n",urb->status);//added by changming HUANG
	
	if (urb->status == -EINPROGRESS) {		
		wait_ms(timeout);
		if(urb->status==-EINPROGRESS)
			status=0;
		else
			status=1;
/*		while (timeout && urb->status == -EINPROGRESS){
			printf("Schedule timeout(hcm)\n");
//			printf("LB MMU WTL Status:%X\n",*((unsigned short*)(0xfffec204)));
			status = timeout = schedule_timeout(timeout);
			}
*/
	} else
		status = 1;

//	printf("The second status:%d\n",status);//added by changming HUANG
	
//	current->state = TASK_RUNNING;
//	remove_wait_queue(&wqh, &wait);

	if (!status) {
		// timeout
		printf("usb_control/bulk_msg: timeout\n");
		usb_unlink_urb(urb);  // remove urb safely
		status = -ETIMEDOUT;
	} else
		status = urb->status;

	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, devrequest *cmd,  void *data, int len, int timeout)
{
	urb_t *urb;
	int retv;
	int length;

	urb = usb_alloc_urb(0);
	if (!urb)
		return -ENOMEM;

  	/* build urb */
	FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,(usb_complete_t)usb_api_blocking_completion,0);

	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 to wait for the message to complete before timing out (if 0 the wait is forever)
 *
 *	This function sends a simple control message to a specified endpoint
 *	and waits for the message to complete, or timeout.
 *	
 *	If successful, it returns 0, othwise a negative error number.
 *
 *	Don't use this function from within an interrupt context, like a
 *	bottom half handler.  If you need a asyncronous message, or need to send
 *	a message from within interrupt context, use usb_submit_urb()
 */
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)
{
	int ret;
	devrequest *dr = (devrequest*)malloc(sizeof(devrequest));	
	
	if (!dr)
		return -ENOMEM;

	dr->requesttype = requesttype;
	dr->request = request;
//	dr->value = cpu_to_le16p(&value);
//	dr->index = cpu_to_le16p(&index);
//	dr->length = cpu_to_le16p(&size);
	dr->value = value;
	dr->index = index;
	dr->length = size;

//	printf("DR->value:%X  value:%X\n",dr->value,value);no problem

	//printf("usb_control_msg");	

	ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);

	free(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 to wait for the message to complete before timing out (if 0 the wait is forever)
 *
 *	This function sends a simple bulk message to a specified endpoint
 *	and waits for the message to complete, or timeout.

⌨️ 快捷键说明

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