?? deviceimpl.java
字號:
/*
* Java USB Library
* Copyright (C) 2000 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package usb.linux;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Locale;
import usb.core.*;
import usb.util.LangCode;
/**
* Provides access to a USB device. To use a device, first make sure that
* you can use the selected configuration. (The Linux kernel makes
* sure a selection is made, although at this writing it doesn't consider
* power consumption or other limitations when doing so.
* Don't use the change-configuration functionality yet.)
*
* @author David Brownell
* @version $Id: DeviceImpl.java,v 1.5 2001/01/02 21:06:43 dbrownell Exp $
*/
final class DeviceImpl extends Device implements DeviceSPI
{
// DEFERRED FUNCTIONALITY:
// - Anything for iso support, including synchFrame control msg
// - Configuration changing (broken support exists)
// - Alternate settings (incomplete support exists)
/** the bus we're connected to */
private final USB usb;
private String path;
// Used for internal synchronization; it should only be known
// within this class. Protects string cache and configuration.
private final Object lock = new Object ();
// XXX Our record of the configuration could be out of date
// since the kernel doesn't yet protect anyone from changes to
// it, even driver software claiming interfaces exposed by
// the current configuration.
private int selectedConfig = -1;
private Configuration currentConfig;
private DeviceDescriptor descriptor;
private boolean checkedStrings;
private int languages [];
// cache just one language; key = Byte (id)
private int cachedLanguage;
private Hashtable stringCache;
/** for hub nodes, lists children; else null */
private DeviceImpl children [];
private DeviceImpl hub;
private int hubPortNum;
// XXX Need kernel support for some device lock to safeguard
// devices against unexpected concurrent operations. Control
// messages can interfere with other work in some cases. This
// is an acknowledged open usbdevfs issue. We should be able to
// workaround other user mode code with O_EXCL. That'd also
// prevent multiple jUSB or libusb processes from working at
// the same time as this, though ...
// package private
DeviceImpl (USB bus, File f, int a)
throws IOException, SecurityException
{
super (null, bus, a);
usb = bus;
path = f.getPath ();
// should only fail if the device unplugged before
// we opened it, or permissions were bogus, or ...
if ((fd = openNative (path)) < 0) {
String message;
message = "can't open device file r/w, " + path;
if (fd == -USBException.EPERM)
throw new SecurityException (message);
else
throw new USBException (message, -fd);
}
// fd's open; NOW we can get the device descriptor
try {
byte buf [];
buf = ControlMessage.getStandardDescriptor (this,
Descriptor.TYPE_DEVICE, (byte) 0, 0, 18);
descriptor = new DeviceDescriptor (this, buf);
} catch (IOException e) {
if (Linux.debug)
System.err.println ("get dev descr fail: "
+ path
+ ", "
+ e.getMessage ());
throw e;
}
// ... and configuration descriptor
getConfiguration ();
if (Linux.trace)
System.err.println ("new: " + path);
}
public String toString ()
{
StringBuffer buf = new StringBuffer ("{Linux Device: ");
String prod = descriptor.getProduct (0);
buf.append (path);
if (prod != null) {
buf.append (" ");
buf.append (prod);
}
buf.append ("}");
return buf.toString ();
}
/** Releases any unreleased system resources. */
protected void finalize ()
throws USBException
{ close (); }
/**
* Immediately closes the device; further operations on this object will
* fail. This is normally done only when the device is being removed.
*/
// package private
void close ()
throws USBException
{
if (fd < 0)
return;
try {
// make sure this isn't usable any more
int status = closeNative (fd);
if (status < 0)
throw new USBException (
"error closing device",
-status);
} finally {
// make sure nobody else sees the device
usb.removeDev (this);
hub = null;
fd = -1;
}
}
/*-------------------------------------------------------------------*/
// implementations of abstract "Device" methods
public Device getHub ()
{ return hub; }
public int getHubPortNum ()
{ return hubPortNum; }
public int getNumPorts ()
{ return (children == null) ? 0 : children.length; }
public DeviceDescriptor getDeviceDescriptor ()
{ return descriptor; }
public Configuration getConfiguration ()
throws IOException
{
if (selectedConfig == -1) {
if (descriptor.getNumConfigurations () != 1) {
ControlMessage msg = new ControlMessage ();
msg.setRequestType ((byte)(msg.DIR_TO_HOST
| msg.TYPE_STANDARD
| msg.RECIPIENT_DEVICE
));
msg.setRequest (msg.GET_CONFIGURATION);
msg.setValue ((short) 0);
msg.setIndex ((short) 0);
msg.setLength (1);
control (msg);
selectedConfig = 0xff & msg.getBuffer ()[0];
} else
selectedConfig = 0;
}
return getConfiguration (selectedConfig);
}
// also a DeviceSPI method
public Device getChild (int port)
{
if (children == null)
return null;
return children [port - 1];
}
/*-------------------------------------------------------------------*/
/**
* Returns the filesystem name for this file.
*/
public String getPath () { return path; }
// uses the system locale ...
// perfect for server/implementation, maybe not for clients.
// Locale is also not available on all systems; may need
// to ignore this if no I18N support is available/used.
private int chooseDefaultLanguage ()
{
if (languages.length == 1)
return languages [0];
Locale dflt = Locale.getDefault ();
int retval = languages [0];
for (int i = 0; i < languages.length; i++) {
Locale current = LangCode.getLocale (languages [i]);
// return exact matches if possible
if (current == dflt)
return languages [i];
// insist on shared language
if (current == null)
continue;
if (!current.getLanguage ().equals (dflt.getLanguage ()))
continue;
// could also check country (return now if same)
// it's OK, and maybe better than our last guess
retval = languages [i];
}
return retval;
}
/**
* Returns the string indexed with the specified ID in the
* default language, or null if there is no such string.
* Use of cached values is preferred.
*
* <p>The default language is the one that is being cached.
* If this is the first request, then the language of the
* default locale is used if it is supported, else the first
* supported language is chosen as a fallback.
*/
public String getString (int id)
throws IOException
{
if (!checkedStrings)
getLanguages ();
if (languages == null || languages.length == 0)
return null;
if (stringCache == null)
return getString (id, chooseDefaultLanguage ());
else
return getString (id, cachedLanguage);
}
/**
* Implementation of {@link usb.core.Device#getString Device.getString}
* which can cache strings in the device's default language.
*/
public String getString (int id, int language)
throws IOException
{
if (id == 0)
return null;
if (id < 0 || id > 0xff)
throw new IllegalArgumentException ();
if (!checkedStrings)
getLanguages ();
if (languages == null || languages.length == 0)
return null;
Byte key = new Byte ((byte) id);
String retval = null;
if (stringCache == null) {
synchronized (lock) {
if (stringCache == null) {
cachedLanguage = language;
stringCache = new Hashtable (7);
}
}
/**/
} else if (stringCache.containsKey (key)) {
Object value = stringCache.get (key);
if (value instanceof String)
return (String) value;
else
return null;
/**/
}
retval = ControlMessage.getString (this, (byte) id, language);
if (retval == null) // negative caching
stringCache.put (key, Boolean.FALSE);
else // positive caching
stringCache.put (key, retval);
return retval;
}
public int [] getLanguages ()
throws IOException
{
synchronized (lock) {
if (!checkedStrings)
languages = ControlMessage.getLanguages (this);
}
if (languages == null)
return null;
int retval [] = new int [languages.length];
for (int i = 0; i < languages.length; i++)
retval [i] = languages [i];
return retval;
}
/**
* Returns the specified configuration.
* This can need to accumulate device-specific smarts.
*/
public Configuration getConfiguration (int index)
throws IOException
{
Configuration retval;
if (index < 0 || index >= descriptor.getNumConfigurations ())
throw new IllegalArgumentException ();
synchronized (lock) {
if (index == selectedConfig && currentConfig != null)
return currentConfig;
// NOTE: we _could_ read 'fd' and bypass control messages
// for the case of the current configuration
retval = new Configuration (this, getConfigBuf (index));
if (index == selectedConfig)
currentConfig = retval;
}
return retval;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -