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

📄 usb.c

📁 linux core 函数例程
💻 C
📖 第 1 页 / 共 5 页
字号:

	/* 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 usbfs; 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 */

	dbg ("kusbd: %s %s %d", argv [0], verb, dev->devnum);
	value = call_usermodehelper (argv [0], argv, envp);
	kfree (buf);
	kfree (envp);
	if (value != 0)
		dbg ("kusbd policy returned 0x%x", 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++) {
		struct usb_interface *interface = &dev->actconfig->interface[ifnum];
		
		/* register this interface with driverfs */
		interface->dev.parent = &dev->dev;
		sprintf (&interface->dev.bus_id[0], "%03d", ifnum);
		sprintf (&interface->dev.name[0], "figure out some name...");
		device_register (&interface->dev);

		/* if this interface hasn't already been claimed */
		if (!usb_interface_claimed(interface)) {
			if (usb_find_interface_driver(dev, ifnum))
				rejected++;
			else
				claimed++;
		}
	}
 
	if (rejected)
		dbg("unhandled interfaces on device");

	if (!claimed) {
		warn("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.",
			dev->devnum,
			dev->descriptor.idVendor,
			dev->descriptor.idProduct);
#ifdef DEBUG
		usb_show_device(dev);
#endif
	}
}

/**
 * usb_alloc_dev - allocate a usb device structure (usbcore-internal)
 * @parent: hub to which device is connected
 * @bus: bus used to access the device
 * Context: !in_interrupt ()
 *
 * Only hub drivers (including virtual root hub drivers for host
 * controllers) should ever call this.
 *
 * This call is synchronous, and may not be used in an interrupt context.
 */
struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus)
{
	struct usb_device *dev;

	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev)
		return NULL;

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

	usb_bus_get(bus);

	if (!parent)
		dev->devpath [0] = '/';
	dev->bus = bus;
	dev->parent = parent;
	atomic_set(&dev->refcnt, 1);
	INIT_LIST_HEAD(&dev->filelist);

	init_MUTEX(&dev->serialize);

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

	return dev;
}

/**
 * usb_get_dev - increments the reference count of the device
 * @dev: the device being referenced
 *
 * Each live reference to a device should be refcounted.
 *
 * Drivers for USB interfaces should normally record such references in
 * their probe() methods, when they bind to an interface, and release
 * them by calling usb_put_dev(), in their disconnect() methods.
 *
 * A pointer to the device with the incremented reference counter is returned.
 */
struct usb_device *usb_get_dev (struct usb_device *dev)
{
	if (dev) {
		atomic_inc (&dev->refcnt);
		return dev;
	}
	return NULL;
}

/**
 * usb_free_dev - free a usb device structure when all users of it are finished.
 * @dev: device that's been disconnected
 * Context: !in_interrupt ()
 *
 * Must be called when a user of a device is finished with it.  When the last
 * user of the device calls this function, the memory of the device is freed.
 *
 * Used by hub and virtual root hub drivers.  The device is completely
 * gone, everything is cleaned up, so it's time to get rid of these last
 * records of this device.
 */
void usb_free_dev(struct usb_device *dev)
{
	if (atomic_dec_and_test(&dev->refcnt)) {
		if (dev->bus->op->deallocate)
			dev->bus->op->deallocate(dev);
		usb_destroy_configuration (dev);
		usb_bus_put (dev->bus);
		kfree (dev);
	}
}

/**
 * usb_alloc_urb - creates a new urb for a USB driver to use
 * @iso_packets: number of iso packets for this urb
 * @mem_flags: the type of memory to allocate, see kmalloc() for a list of
 *	valid options for this.
 *
 * Creates an urb for the USB driver to use, initializes a few internal
 * structures, incrementes the usage counter, 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 must call usb_free_urb() when it is finished with the urb.
 */
struct urb *usb_alloc_urb(int iso_packets, int mem_flags)
{
	struct urb *urb;

	urb = (struct urb *)kmalloc(sizeof(struct urb) + 
		iso_packets * sizeof(struct usb_iso_packet_descriptor),
		mem_flags);
	if (!urb) {
		err("alloc_urb: kmalloc failed");
		return NULL;
	}

	memset(urb, 0, sizeof(*urb));
	urb->count = (atomic_t)ATOMIC_INIT(1);
	spin_lock_init(&urb->lock);

	return urb;
}

/**
 * usb_free_urb - frees the memory used by a urb when all users of it are finished
 * @urb: pointer to the urb to free
 *
 * Must be called when a user of a urb is finished with it.  When the last user
 * of the urb calls this function, the memory of the urb is freed.
 *
 * Note: The transfer buffer associated with the urb is not freed, that must be
 * done elsewhere.
 */
void usb_free_urb(struct urb *urb)
{
	if (urb)
		if (atomic_dec_and_test(&urb->count))
			kfree(urb);
}

/**
 * usb_get_urb - increments the reference count of the urb
 * @urb: pointer to the urb to modify
 *
 * This must be  called whenever a urb is transfered from a device driver to a
 * host controller driver.  This allows proper reference counting to happen
 * for urbs.
 *
 * A pointer to the urb with the incremented reference counter is returned.
 */
struct urb * usb_get_urb(struct urb *urb)
{
	if (urb) {
		atomic_inc(&urb->count);
		return urb;
	} else
		return NULL;
}
		
		
/*-------------------------------------------------------------------*/

/**
 * usb_submit_urb - asynchronously issue a transfer request for an endpoint
 * @urb: pointer to the urb describing the request
 * @mem_flags: the type of memory to allocate, see kmalloc() for a list
 *	of valid options for this.
 *
 * This submits a transfer request, and transfers control of the URB
 * describing that request to the USB subsystem.  Request completion will
 * indicated later, asynchronously, by calling the completion handler.
 * This call may be issued in interrupt context.
 *
 * The caller must have correctly initialized the URB before submitting
 * it.  Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are
 * available to ensure that most fields are correctly initialized, for
 * the particular kind of transfer, although they will not initialize
 * any transfer flags.
 *
 * Successful submissions return 0; otherwise this routine returns a
 * negative error number.  If the submission is successful, the complete
 * fuction of the urb will be called when the USB host driver is
 * finished with the urb (either a successful transmission, or some
 * error case.)
 *
 * Unreserved Bandwidth Transfers:
 *
 * Bulk or control requests complete only once.  When the completion
 * function is called, control of the URB is returned to the device
 * driver which issued the request.  The completion handler may then
 * immediately free or reuse that URB.
 *
 * Bulk URBs will be queued if the USB_QUEUE_BULK transfer flag is set
 * in the URB.  This can be used to maximize bandwidth utilization by
 * letting the USB controller start work on the next URB without any
 * delay to report completion (scheduling and processing an interrupt)
 * and then submit that next request.
 *
 * For control endpoints, the synchronous usb_control_msg() call is
 * often used (in non-interrupt context) instead of this call.
 *
 * Reserved Bandwidth Transfers:
 *
 * Periodic URBs (interrupt or isochronous) are completed repeatedly,
 * until the original request is aborted.  When the completion callback
 * indicates the URB has been unlinked (with a special status code),
 * control of that URB returns to the device driver.  Otherwise, the
 * completion handler does not control the URB, and should not change
 * any of its fields.
 *
 * Note that isochronous URBs should be submitted in a "ring" data
 * structure (using urb->next) to ensure that they are resubmitted
 * appropriately.
 *
 * If the USB subsystem can't reserve sufficient bandwidth to perform
 * the periodic request, and bandwidth reservation is being done for
 * this controller, submitting such a periodic request will fail.
 *
 * Memory Flags:
 *
 * General rules for how to decide which mem_flags to use:
 * 
 * Basically the rules are the same as for kmalloc.  There are four
 * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and
 * GFP_ATOMIC.
 *
 * GFP_NOFS is not ever used, as it has not been implemented yet.
 *
 * There are three situations you must use GFP_ATOMIC.
 *    a) you are inside a completion handler, an interrupt, bottom half,
 *       tasklet or timer.
 *    b) you are holding a spinlock or rwlock (does not apply to
 *       semaphores)
 *    c) current->state != TASK_RUNNING, this is the case only after
 *       you've changed it.
 * 
 * GFP_NOIO is used in the block io path and error handling of storage
 * devices.
 *
 * All other situations use GFP_KERNEL.
 *
 * Specfic rules for how to decide which mem_flags to use:
 *
 *    - start_xmit, timeout, and receive methods of network drivers must
 *      use GFP_ATOMIC (spinlock)
 *    - queuecommand methods of scsi drivers must use GFP_ATOMIC (spinlock)
 *    - If you use a kernel thread with a network driver you must use
 *      GFP_NOIO, unless b) or c) apply
 *    - After you have done a down() you use GFP_KERNEL, unless b) or c)
 *      apply or your are in a storage driver's block io path
 *    - probe and disconnect use GFP_KERNEL unless b) or c) apply
 *    - Changing firmware on a running storage or net device uses
 *      GFP_NOIO, unless b) or c) apply
 *
 */
int usb_submit_urb(struct urb *urb, int mem_flags)
{

	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op) {
		if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) {
			err("%s: pipe %x has invalid size (<= 0)", __FUNCTION__, urb->pipe);
			return -EMSGSIZE;
		}
		return urb->dev->bus->op->submit_urb(urb, mem_flags);
	}
	return -ENODEV;
}

/*-------------------------------------------------------------------*/

/**
 * usb_unlink_urb - abort/cancel a transfer request for an endpoint
 * @urb: pointer to urb describing a previously submitted request
 *
 * This routine cancels an in-progress request.  The requests's
 * completion handler will be called with a status code indicating
 * that the request has been canceled, and that control of the URB
 * has been returned to that device driver.  This is the only way
 * to stop an interrupt transfer, so long as the device is connected.
 *
 * When the USB_ASYNC_UNLINK transfer flag for the URB is clear, this
 * request is synchronous.  Success is indicated by returning zero,
 * at which time the urb will have been unlinked,
 * and the completion function will see status -ENOENT.  Failure is
 * indicated by any other return value.  This mode may not be used
 * when unlinking an urb from an interrupt context, such as a bottom
 * half or a completion handler,
 *
 * When the USB_ASYNC_UNLINK transfer flag for the URB is set, this
 * request is asynchronous.  Success is indicated by returning -EINPROGRESS,
 * at which time the urb will normally not have been unlinked,
 * and the completion function will see status -ECONNRESET.  Failure is
 * indicated by any other return value.
 */
int usb_unlink_urb(struct urb *urb)
{
	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op)
		return urb->dev->bus->op->unlink_urb(urb);
	else
		return -ENODEV;
}
/*-------------------------------------------------------------------*
 *                         SYNCHRONOUS CALLS                         *
 *-------------------------------------------------------------------*/

struct usb_api_data {
	wait_queue_head_t wqh;
	int done;
};

static void usb_api_blocking_completion(struct urb *urb)
{
	struct usb_api_data *awd = (struct usb_api_data *)urb->context;

	awd->done = 1;
	wmb();
	wake_up(&awd->wqh);
}

// Starts urb and waits for completion or timeout
static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
{ 
	DECLARE_WAITQUEUE(wait, current);
	struct usb_api_data awd;
	int status;

	init_waitqueue_head(&awd.wqh); 	
	awd.done = 0;

	set_current_state(TASK_UNINTERRUPTIBLE);

⌨️ 快捷键说明

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