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

📄 usb.c

📁 ReactOs中的USB驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
 * @dev: the device whose bus is being queried
 *
 * Returns the current frame number for the USB host controller
 * used with the given USB device.  This can be used when scheduling
 * isochronous requests.
 *
 * Note that different kinds of host controller have different
 * "scheduling horizons".  While one type might support scheduling only
 * 32 frames into the future, others could support scheduling up to
 * 1024 frames into the future.
 */
int usb_get_current_frame_number(struct usb_device *dev)
{
	return dev->bus->op->get_frame_number (dev);
}

/*-------------------------------------------------------------------*/
/*
 * __usb_get_extra_descriptor() finds a descriptor of specific type in the
 * extra field of the interface and endpoint descriptor structs.
 */

int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
{
	struct usb_descriptor_header *header;

	while (size >= sizeof(struct usb_descriptor_header)) {
		header = (struct usb_descriptor_header *)buffer;

		if (header->bLength < 2) {
			err("invalid descriptor length of %d", header->bLength);
			return -1;
		}

		if (header->bDescriptorType == type) {
			*ptr = header;
			return 0;
		}

		buffer += header->bLength;
		size -= header->bLength;
	}
	return -1;
}

/**
 * usb_disconnect - disconnect a device (usbcore-internal)
 * @pdev: pointer to device being disconnected
 * Context: !in_interrupt ()
 *
 * Something got disconnected. Get rid of it, and all of its children.
 *
 * 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.
 */
void usb_disconnect(struct usb_device **pdev)
{
	struct usb_device	*dev = *pdev;
	struct usb_bus		*bus;
	struct usb_operations	*ops;
	int			i;

	might_sleep ();

	if (!dev) {
//		pr_debug ("%s nodev\n", __FUNCTION__);
		DPRINT ("%s nodev\n", __FUNCTION__);
		return;
	}
	bus = dev->bus;
	if (!bus) {
//		pr_debug ("%s nobus\n", __FUNCTION__);
		DPRINT ("%s nobus\n", __FUNCTION__);
		return;
	}
	ops = bus->op;

	*pdev = NULL;

	/* mark the device as inactive, so any further urb submissions for
	 * this device will fail.
	 */
	dev->state = USB_STATE_NOTATTACHED;

	dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum);

	/* Free up all the children before we remove this device */
	for (i = 0; i < USB_MAXCHILDREN; i++) {
		struct usb_device **child = dev->children + i;
		if (*child)
			usb_disconnect(child);
	}

	/* disconnect() drivers from interfaces (a key side effect) */
	dev_dbg (&dev->dev, "unregistering interfaces\n");
	if (dev->actconfig) {
		for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
			struct usb_interface	*interface;

			/* remove this interface */
			interface = &dev->actconfig->interface[i];
			device_unregister(&interface->dev);
		}
	}

	/* deallocate hcd/hardware state */
	if (ops->disable) {
		void	(*disable)(struct usb_device *, int) = ops->disable;

		for (i = 0; i < 15; i++) {
			disable (dev, i);
			disable (dev, USB_DIR_IN | i);
		}
	}

	dev_dbg (&dev->dev, "unregistering device\n");
	/* Free the device number and remove the /proc/bus/usb entry */
	if (dev->devnum > 0) {
		clear_bit(dev->devnum, dev->bus->devmap.devicemap);
		usbfs_remove_device(dev);
	}
	device_unregister(&dev->dev);

	/* Decrement the reference count, it'll auto free everything when */
	/* it hits 0 which could very well be now */
	usb_put_dev(dev);
}

/**
 * usb_connect - pick device address (usbcore-internal)
 * @dev: newly detected device (in DEFAULT state)
 *
 * Picks a device address.  It's up to the hub (or root hub) driver
 * to handle and manage enumeration, starting from the DEFAULT state.
 * Only hub drivers (including virtual root hub drivers for host
 * controllers) should ever call this.
 */
void STDCALL usb_connect(struct usb_device *dev)
{
	int devnum;
	// FIXME needs locking for SMP!!
	/* why? this is called only from the hub thread, 
	 * which hopefully doesn't run on multiple CPU's simultaneously 8-)
	 * ... it's also called from modprobe/rmmod/apmd threads as part
	 * of virtual root hub init/reinit.  In the init case, the hub code 
	 * won't have seen this, but not so for reinit ... 
	 */
	dev->descriptor.bMaxPacketSize0 = 8;  /* Start off at 8 bytes  */

	/* Try to allocate the next devnum beginning at bus->devnum_next. */
	devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
	if (devnum >= 128)
		devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);

	dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);

	if (devnum < 128) {
		set_bit(devnum, dev->bus->devmap.devicemap);
		dev->devnum = devnum;
	}
}

/**
 * usb_choose_address - pick device address (usbcore-internal)
 * @dev: newly detected device (in DEFAULT state)
 *
 * Picks a device address.  It's up to the hub (or root hub) driver
 * to handle and manage enumeration, starting from the DEFAULT state.
 * Only hub drivers (but not virtual root hub drivers for host
 * controllers) should ever call this.
 */
void usb_choose_address(struct usb_device *dev)
{
	int devnum;
	// FIXME needs locking for SMP!!
	/* why? this is called only from the hub thread, 
	 * which hopefully doesn't run on multiple CPU's simultaneously 8-)
	 */

	/* Try to allocate the next devnum beginning at bus->devnum_next. */
	devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
	if (devnum >= 128)
		devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);

	dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);

	if (devnum < 128) {
		set_bit(devnum, dev->bus->devmap.devicemap);
		dev->devnum = devnum;
	}
}

// hub-only!! ... and only exported for reset/reinit path.
// otherwise used internally, for usb_new_device()
int usb_set_address(struct usb_device *dev)
{
	int retval;

	if (dev->devnum == 0)
		return -EINVAL;
	if (dev->state != USB_STATE_DEFAULT && dev->state != USB_STATE_ADDRESS)
		return -EINVAL;
	retval = usb_control_msg(dev, usb_snddefctrl(dev), USB_REQ_SET_ADDRESS,
		0, dev->devnum, 0, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
	if (retval == 0)
		dev->state = USB_STATE_ADDRESS;
	return retval;
}


/* improve on the default device description, if we can ... and
 * while we're at it, maybe show the vendor and product strings.
 */
static void set_device_description (struct usb_device *dev)
{
	void    *buf;
	int	mfgr = dev->descriptor.iManufacturer;
	int	prod = dev->descriptor.iProduct;
	int	vendor_id = dev->descriptor.idVendor;
	int	product_id = dev->descriptor.idProduct;
	char	*mfgr_str, *prod_str;

	/* set default; keep it if there are no strings, or kmalloc fails */
	sprintf (dev->dev.name, "USB device %04x:%04x",
		 vendor_id, product_id);

	if (!(buf = kmalloc(256 * 2, GFP_KERNEL)))
		return;
	
	prod_str = (char *) buf;
	mfgr_str = (char *) buf + 256;

	if (prod && usb_string (dev, prod, prod_str, 256) > 0) {
#ifdef DEBUG
		dev_printk (KERN_INFO, &dev->dev, "Product: %s\n", prod_str);
#endif
	} else {
		prod_str = 0;
	}

	if (mfgr && usb_string (dev, mfgr, mfgr_str, 256) > 0) {
#ifdef DEBUG
		dev_printk (KERN_INFO, &dev->dev, "Manufacturer: %s\n", mfgr_str);
#endif
	} else {
		mfgr_str = 0;
	}

	/* much like pci ... describe as either:
	 * - both strings:   'product descr (vendor descr)'
	 * - product only:   'product descr (USB device vvvv:pppp)'
	 * - vendor only:    'USB device vvvv:pppp (vendor descr)'
	 * - neither string: 'USB device vvvv:pppp'
	 */

	if (prod_str && mfgr_str) {

		snprintf(dev->dev.name, sizeof dev->dev.name,
			 "%s (%s)", prod_str, mfgr_str);
	} else if (prod_str) {
		snprintf(dev->dev.name, sizeof dev->dev.name,
			 "%s (USB device %04x:%04x)",
			 prod_str, vendor_id, product_id);

	} else if (mfgr_str) {
		snprintf(dev->dev.name, sizeof dev->dev.name,
			 "USB device %04x:%04x (%s)",
			 vendor_id, product_id, mfgr_str);
	}
	usbprintk("USB connected: %s\n",dev->dev.name);
	kfree(buf);
}

/*
 * By the time we get here, we chose a new device address
 * and is in the default state. We need to identify the thing and
 * get the ball rolling..
 *
 * Returns 0 for success, != 0 for error.
 *
 * This call is synchronous, and may not be used in an interrupt context.
 *
 * Only hub drivers (including virtual root hub drivers for host
 * controllers) should ever call this.
 */
#define NEW_DEVICE_RETRYS	2
#define SET_ADDRESS_RETRYS	20
int usb_new_device(struct usb_device *dev, struct device *parent)
{
	int err = -EINVAL;
	int i;
	int j;

	/*
	 * Set the driver for the usb device to point to the "generic" driver.
	 * This prevents the main usb device from being sent to the usb bus
	 * probe function.  Yes, it's a hack, but a nice one :)
	 *
	 * Do it asap, so more driver model stuff (like the device.h message
	 * utilities) can be used in hcd submit/unlink code paths.
	 */
	usb_generic_driver.bus = &usb_bus_type;
	dev->dev.parent = parent;
	dev->dev.driver = &usb_generic_driver;
	dev->dev.bus = &usb_bus_type;
	dev->dev.release = usb_release_dev;
	dev->dev.driver_data = &usb_generic_driver_data;
	usb_get_dev(dev);
	if (dev->dev.bus_id[0] == 0)
		sprintf (&dev->dev.bus_id[0], "%d-%s",
			 dev->bus->busnum, dev->devpath);

	/* dma masks come from the controller; readonly, except to hcd */
	dev->dev.dma_mask = parent->dma_mask;

	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
	 * it's fixed size except for full speed devices.
	 */
	switch (dev->speed) {
	case USB_SPEED_HIGH:		/* fixed at 64 */
		i = 64;
		break;
	case USB_SPEED_FULL:		/* 8, 16, 32, or 64 */
		/* to determine the ep0 maxpacket size, read the first 8
		 * bytes from the device descriptor to get bMaxPacketSize0;
		 * then correct our initial (small) guess.
		 */
		// FALLTHROUGH
	case USB_SPEED_LOW:		/* fixed at 8 */
		i = 8;
		break;
	default:
		goto fail;
	}
	dev->epmaxpacketin [0] = i;
	dev->epmaxpacketout[0] = i;

	for (i = 0; i < NEW_DEVICE_RETRYS; ++i) {

		for (j = 0; j < SET_ADDRESS_RETRYS; ++j) {
			err = usb_set_address(dev);
			if (err >= 0)
				break;
			wait_ms(5);
		}
		if (err < 0) {
			dev_err(&dev->dev, "USB device not accepting new address=%d (error=%d)\n",
				dev->devnum, err);
			goto fail;
		}

		wait_ms(10);	/* Let the SET_ADDRESS settle */

		/* high and low speed devices don't need this... */
		err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
		if (err >= 8)
			break;
		wait_ms(100);
	}

	if (err < 8) {
		dev_err(&dev->dev, "device descriptor read/8, error %d\n", err);
		goto fail;
	}
	if (dev->speed == USB_SPEED_FULL) {
		//usb_disable_endpoint(dev, 0);
		usb_endpoint_running(dev, 0, 1);
		usb_endpoint_running(dev, 0, 0);
		dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
		dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
	}

	/* USB device state == addressed ... still not usable */

	err = usb_get_device_descriptor(dev);
	if (err < (signed)sizeof(dev->descriptor)) {
		dev_err(&dev->dev, "device descriptor read/all, error %d\n", err);
		goto fail;
	}

	err = usb_get_configuration(dev);
	if (err < 0) {
		dev_err(&dev->dev, "can't read configurations, error %d\n",
			err);
		goto fail;
	}

	/* we set the default configuration here */
	err = usb_set_configuration(dev, dev->config[0].desc.bConfigurationValue);
	if (err) {
		dev_err(&dev->dev, "failed to set device %d default configuration (error=%d)\n",
			dev->devnum, err);
		goto fail;
	}

	/* USB device state == configured ... tell the world! */

	dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
		dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
	set_device_description (dev);

#ifdef DEBUG
	if (dev->descriptor.iSerialNumber)
		usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif

⌨️ 快捷键说明

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