usbhubmonitor.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 344 行

JAVA
344
字号
/*
 * $Id: USBHubMonitor.java,v 1.2 2003/12/10 01:31:39 olegv Exp $
 */
package org.jnode.driver.usb;

import org.apache.log4j.Logger;
import org.jnode.driver.Device;
import org.jnode.driver.DeviceAlreadyRegisteredException;
import org.jnode.driver.DeviceManager;
import org.jnode.driver.DriverException;
import org.jnode.util.NumberUtils;

/**
 * Class used to watch an USB HUB for changes in the connection status of its ports.
 * 
 * To have the best chance of success we do things in the exact same order as Windoze98. This
 * should not be necessary, but some devices do not follow the USB specs to the letter.
 * 
 * These are the events on the bus when a hub is attached:
 * <ul>
 * <li>Get device and config descriptors (see attach code)</li>
 * <li>Get hub descriptor (see above)</li>
 * <li>For all ports
 * <ul>
 * <li>turn on power</li>
 * <li>wait for power to become stable</li>
 * </ul>
 * </li>
 * <li>For all ports
 * <ul>
 * <li>clear C_PORT_CONNECTION</li>
 * </ul>
 * </li>
 * <li>For all ports
 * <ul>
 * <li>get port status</li>
 * <li>if device connected
 * <ul>
 * <li>wait 100 ms</li>
 * <li>turn on reset</li>
 * <li>wait</li>
 * <li>clear C_PORT_RESET</li>
 * <li>get port status</li>
 * <li>proceed with device attachment</li>
 * </ul>
 * </li>
 * </ul>
 * </li>
 * </ul>
 * 
 * @author Ewout Prangsma (epr@users.sourceforge.net)
 */
public class USBHubMonitor implements USBConstants {

	/** My logger */
	protected final Logger log = Logger.getLogger(getClass());
	/** The hub device */
	private final Device hubDevice;
	/** The Hub API */
	private final USBHubAPI hub;
	/** The device manager */
	private final DeviceManager dm;
	/** The monitor thread (if started) */
	private USBHubMonitorThread thread;

	/**
	 * Initialize a new instance.
	 * 
	 * @param hub
	 */
	public USBHubMonitor(Device hubDevice, USBHubAPI hub) {
		this.hubDevice = hubDevice;
		this.hub = hub;
		this.dm = hubDevice.getManager();
	}

	/**
	 * Do the actual monitoring.
	 */
	protected void checkStatus(boolean first) {
		try {
			final int ports = hub.getNumPorts();
			for (int port = 0; port < ports; port++) {
				if (first) {
					hub.setPortEnabled(port, false);
					sleep(100);
					hub.resetPort(port);
					sleep(100);
				}
				if (first || hub.isPortConnectionStatusChanged(port)) {
					portConnectionStatusChanged(port);
				}
			}
		} catch (USBException ex) {
			log.error("Error in portConnectionStatusChanged", ex);
		}
	}

	/**
	 * The connection status of a given port has changed.
	 * 
	 * @param port
	 */
	protected void portConnectionStatusChanged(int port) throws USBException {
		log.debug("USB hub connection status changed for port " + port);

		if (hub.isPortConnected(port)) {
			//log.debug("Port " + port + " is connected");
			// Wait for at least 100ms to stabilize
			sleep(100);
			// Reset the port
			hub.resetPort(port);
			// Wait a while for reset to stabilize
			sleep(100);

			final int speed;
			if (hub.isPortConnectedToLowSpeed(port)) {
				speed = USB_SPEED_LOW;
				log.debug("Port " + port + " is connected to lowspeed device");
			} else if (hub.isPortConnectedToHighSpeed(port)) {
				log.debug("Port " + port + " is connected to highspeed device");
				speed = USB_SPEED_HIGH;
			} else {
				log.debug("Port " + port + " is connected to fullspeed device");
				speed = USB_SPEED_FULL;
			}

			// Create the new device
			//log.debug("Creating USBDevice");
			final USBDevice dev = new USBDevice(hub.getUSBBus(), speed);
			dev.getDefaultControlPipe().open();

			// Now set the address
			//log.debug("Set the address");
			final int devId = dev.getUSBBus().allocDeviceID();
			try {
				// Set the device address
				dev.setAddress(devId);
				log.debug("Now using address 0x" + NumberUtils.hex(devId, 2));
				sleep(100); // Let the address settle
				log.debug("After sleep");

				// Determine the maximum packet size by fetching 8 bytes of device descriptor.
				//log.debug("Fetching first 8 bytes of device descriptor");
				final DeviceDescriptor devDescr = new DeviceDescriptor();
				dev.readDescriptor(USB_RECIP_DEVICE, USB_DT_DEVICE, 0, 0, 8, devDescr);
				dev.setDescriptor(devDescr);
				log.debug("devDescr[0-7]=" + devDescr + ", len=" + devDescr.getLength());

				// Fetch the complete device descriptor.
				dev.readDescriptor(USB_RECIP_DEVICE, USB_DT_DEVICE, 0, 0, USB_DT_DEVICE_SIZE, devDescr);
				log.debug("read devDescr=" + devDescr);
				dev.setFullDescriptor(devDescr);
				log.debug("Full devDescr=" + devDescr);

				// Get all configurations.
				final int confCount = devDescr.getNumConfigurations();
				for (int i = 0; i < confCount; i++) {
					final USBConfiguration conf = getConfiguration(dev, i);
					dev.setConfiguration(i, conf);
					log.debug("Read configuration " + conf);
				}
				// Set configuration 0
				dev.setConfiguration(dev.getConfiguration(0));

				// Load the strings of the device descriptor
				devDescr.loadStrings(dev);
				log.debug("Got descriptor " + devDescr);

				// Register the device with the HUB
				log.debug("hub.setDevice");
				hub.setDevice(dev, port);
				// Register the device with the device manager
				log.debug("dm.register");
				dm.register(dev);

				log.debug("Found USB device " + devDescr);
			} catch (USBException ex) {
				log.debug("Port status 0x" + NumberUtils.hex(hub.getPortStatus(port)));
				dev.getUSBBus().freeDeviceID(devId);
				hub.unsetDevice(port);
				throw ex;
			} catch (DriverException ex) {
				dev.getUSBBus().freeDeviceID(devId);
				hub.unsetDevice(port);
				throw new USBException(ex);
			} catch (DeviceAlreadyRegisteredException ex) {
				dev.getUSBBus().freeDeviceID(devId);
				hub.unsetDevice(port);
				throw new USBException(ex);
			}

		} else {
			log.debug("Port " + port + " is not connected");
			final USBDevice dev = hub.getDevice(port);
			if (dev != null) {
				try {
					// Unregister the device
					dm.unregister(dev);
				} catch (DriverException ex) {
					log.error("Error unregistering disconnected USB device", ex);
				}
				// Remove the device from the HUB
				hub.unsetDevice(port);
			}
			hub.setPortEnabled(port, false);
		}

		// Clear the connection status
		hub.clearPortConnectionStatusChanged(port);
	}

	/**
	 * Gets a specific configuration for the given device.
	 * 
	 * @param dev
	 * @param confNum
	 */
	private final USBConfiguration getConfiguration(USBDevice dev, int confNum) throws USBException {

		// First read enough to get the wTotalLength
		final ConfigurationDescriptor initDescr = new ConfigurationDescriptor();
		dev.readDescriptor(USB_RECIP_DEVICE, USB_DT_CONFIG, confNum, 0, USB_DT_CONFIG_SIZE, initDescr);

		// Now get the full configuration data
		final byte[] data = new byte[initDescr.getTotalLength()];
		final USBPacket dataP = new USBPacket(data);
		dev.readDescriptor(USB_RECIP_DEVICE, USB_DT_CONFIG, confNum, 0, data.length, dataP);

		// Get the configuration strings
		final ConfigurationDescriptor confDescr = new ConfigurationDescriptor(data, 0, USB_DT_CONFIG_SIZE);
		confDescr.loadStrings(dev);

		// Create the configuration
		final USBConfiguration conf = new USBConfiguration(dev, confDescr);

		// Parse the interface descriptors
		final int intfCount = confDescr.getNumInterfaces();
		int offset = confDescr.getLength();
		for (int i = 0; i < intfCount; i++) {
			final InterfaceDescriptor intfDescr = new InterfaceDescriptor(data, offset, USB_DT_INTERFACE_SIZE);
			intfDescr.loadStrings(dev);
			offset += intfDescr.getLength();
			final USBInterface intf = new USBInterface(conf, intfDescr);
			conf.setInterface(i, intf);

			// Parse the endpoint descriptors
			final int epCount = intfDescr.getNumEndPoints();
			for (int epIndex = 0; epIndex < epCount;) {
				final int dType = dataP.getByte(offset + 1);
				if (dType == USB_DT_ENDPOINT) {
					// It is an e
					final EndPointDescriptor epDescr = new EndPointDescriptor(data, offset, USB_DT_ENDPOINT_SIZE);
					offset += epDescr.getLength();
					final USBEndPoint ep = new USBEndPoint(intf, epDescr);
					intf.setEndPoint(epIndex++, ep);
				} else {
					// Skip this unknown descriptor
					log.debug("Skipping unknown descriptor type " + dType);
					offset += dataP.getByte(offset); // Length
				}
			}
		}

		return conf;
	}

	/**
	 * Sleep a while
	 * 
	 * @param ms
	 */
	private void sleep(long ms) {
		try {
			Thread.sleep(ms);
		} catch (InterruptedException ex) {
			// Ignore
		}
	}

	/**
	 * @see org.jnode.driver.DeviceListener#deviceStarted(org.jnode.driver.Device)
	 */
	public void startMonitor() {
		if (thread == null) {
			thread = new USBHubMonitorThread("HubMonitor-" + hubDevice.getId());
			thread.start();
		}
	}

	/**
	 * @see org.jnode.driver.DeviceListener#deviceStop(org.jnode.driver.Device)
	 */
	public void stopMonitor() {
		final USBHubMonitorThread thread = this.thread;
		if (thread != null) {
			thread.stopThread();
			try {
				thread.join(2000);
			} catch (InterruptedException ex) {
				// Ignore
			}
		}
		this.thread = null;
	}

	/**
	 * The actual monitor thread.
	 * 
	 * @author Ewout Prangsma (epr@users.sourceforge.net)
	 */
	class USBHubMonitorThread extends Thread {

		private boolean stop;

		public USBHubMonitorThread(String name) {
			super(name);
			this.stop = false;
		}

		public void stopThread() {
			this.stop = true;
		}

		public void run() {
			boolean first = true;
			while (!stop) {
				try {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException ex) {
						stop = true;
					}
					checkStatus(first);
				} catch (Exception ex) {
					log.error("Error in USBHubMonitor", ex);
				}
				first = false;
			}
		}

	}
}

⌨️ 快捷键说明

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