USB defines class code information that is used to identify a device’s functionality and to nominally load a device driver based on that functionality. The information is contained in three bytes with the names Base Class, SubClass, and Protocol. (Note that ‘Base Class’ is used in this description to identify the first byte of the Class Code triple. That terminology is not used in the USB Specification). There are two places on a device where class code information can be placed.One place is in the Device Descriptor, and the other is in Interface Descriptors. Some defined class codes are allowed to be used only in a Device Descriptor, others can be used in both Device and Interface Descriptors, and some can only be used in Interface Descriptors. The table below shows the currently defined set of Base Class values, what the generic usage is, and where that Base Class can be used (either Device or Interface Descriptors or both).
Last Update: June 15, 2016
Base Class |
Descriptor Usage |
Description |
00h |
Device |
|
01h |
Interface |
|
02h |
Both |
|
03h |
Interface |
|
05h |
Interface |
|
06h |
Interface |
|
07h |
Interface |
|
08h |
Interface |
|
09h |
Device |
|
0Ah |
Interface |
|
0Bh |
Interface |
|
0Dh |
Interface |
|
0Eh |
Interface |
|
0Fh |
Interface |
|
10h |
Interface |
|
11h |
Device |
|
12h |
Interface |
|
DCh |
Both |
|
E0h |
Interface |
|
EFh |
Both |
|
FEh |
Interface |
|
FFh |
Both |
Base Class Descriptor Usage Description
00h Device Use class information in the Interface Descriptors种类信息定义在接口描述符中
01h Interface Audio音频设备
02h Both Communications&CDC通信设备
03h Interface HID(Human Interface Device)人机接口设备
05h Interface Physical物理设备
06h Interface Image图像设备
07h Interface Printer打印机
08h Interface Mass Storage 大容量存储
09h Device Hub集线器
0Ah Interface CDC-Data通信设备
0Bh Interface Smart Card智能卡
0Dh Interface Content Security内容安全设备
0Eh Interface Video视频设备
0Fh Interface Personal Healthcare个人健康设备
10h Interface Audio/Video Devices声音/视频设备
11h Device Billboard Device Class广播牌设备
12h Interface USB Type-C Bridge Class
DCh Both Diagnostic Device
E0h Interface Wireless Controller
EFh Both Miscellaneous
FEh Interface Application Specific
FFh Both Vendor Specific
参考文章:https://www.usb.org/defined-class-codes
Linux对USB设备类型定义
在kernel中,有两个结构体的相关成员表征USB设备的类型,第一个usb_device_descriptor:
include/uapi/linux/usb/ch9.h
/* USB_DT_DEVICE: Device descriptor */
struct usb_device_descriptor {
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
} __attribute__ ((packed));
bDeviceClass成员值区别不同的USB设备,如果该值为0呢?看上边:
Base Class
Descriptor Usage
Description
00h
Device
Use class information in the Interface Descriptors
就在第二个结构体usb_interface_descriptor中:
include/uapi/linux/usb/ch9.h
struct usb_interface_descriptor {
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
} __attribute__ ((packed));
bInterfaceClass成员即是。
比如,对于USB打印机设备,定义如下:
include/uapi/linux/usb/ch9.h
/*
* Device and/or Interface Class codes
* as found in bDeviceClass or bInterfaceClass
* and defined by www.usb.org documents
*/
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PHYSICAL 5
#define USB_CLASS_STILL_IMAGE 6
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_CDC_DATA 0x0a
#define USB_CLASS_CSCID 0x0b /* chip+ smart card */
#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
#define USB_CLASS_MISC 0xef
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
drivers/usb/gadget/printer.c
static struct usb_interface_descriptor intf_desc = {
.bLength = sizeof intf_desc,
.bDescriptorType = USB_DT_INTERFACE,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_PRINTER,
.bInterfaceSubClass = 1, /* Printer Sub-Class */
.bInterfaceProtocol = 2, /* Bi-Directional */
.iInterface = 0
};
对上了,不是?!
四、JNI和Framework层
JNI层的usbhost.c文件为我们获取Linux driver中USB设备的信息提供了便利,除了USB设备类型,还可以得到USB设备的厂商名称、产品名称、***等:
system/core/libusbhost/usbhost.c
usbhost.c该文件中提供的方法在JNI中调用:
frameworks/base/services/jni/com_android_server_UsbHostManager.cpp
上面代码截图信息量很大!很重要!很重要!很重要!很重要!重要的地方说四遍。
1、调用usbhost.c文件中方法获取USB设备信息
2、获取的信息一部分传到UsbInterface.java,APP部分调用UsbInterface类获取信息
frameworks/base/core/java/android/hardware/usb/UsbInterface.java
public class UsbInterface implements Parcelable {
private final int mId;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
private final Parcelable[] mEndpoints;
}
3、获取的信息另一部分通过调用UsbHostManager.java中的usbDeviceAdded(4.4+版本是beginUsbDeviceAdded/endUsbDeviceAdded)方法,把信息写到UsbDevice.java中,APP部分调用UsbDevice类获取信息:
frameworks/base/core/java/android/hardware/usb/UsbDevice.java
public class UsbDevice implements Parcelable {
private final String mName;
private final int mVendorId;
private final int mProductId;
private final int mClass;
private final int mSubclass;
private final int mProtocol;
private final Parcelable[] mInterfaces;
}
接下来,我们就看下如此关键的usbDeviceAdded(4.4+版本是beginUsbDeviceAdded/endUsbDeviceAdded)方法:
frameworks/base/services/java/com/android/server/usb/UsbHostManager.java
private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
int deviceClass, int deviceSubclass, int deviceProtocol,
String manufacturerName, String productName, String serialNumber) {
// 位于BlackListed中的USB设备系统不予管理,比如USB HUB,USB鼠标等
if (isBlackListed(deviceName) ||
isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
return false;
}
synchronized (mLock) {
if (mDevices.get(deviceName) != null) {
Slog.w(TAG, "device already on mDevices list: " + deviceName);
return false;
}
if (mNewDevice != null) {
Slog.e(TAG, "mNewDevice is not null in endUsbDeviceAdded");
return false;
}
mNewDevice = new UsbDevice(deviceName, vendorID, productID,
deviceClass, deviceSubclass, deviceProtocol,
manufacturerName, productName, serialNumber);
mNewConfigurations = new ArrayList<UsbConfiguration>();
mNewInterfaces = new ArrayList<UsbInterface>();
mNewEndpoints = new ArrayList<UsbEndpoint>();
}
return true;
}
private void endUsbDeviceAdded() {
synchronized (mLock) {
if (mNewDevice != null) {
mNewDevice.setConfigurations(
mNewConfigurations.toArray(new UsbConfiguration[mNewConfigurations.size()]));
mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
}
}
}
五、APP层
经过上面分析,获取USB设备类型等信息,已经心有成竹了,使用UsbDevice、UsbInterface两个类即可。其中,UsbInterface类是包含在UsbDevice类中的:
frameworks/base/core/java/android/hardware/usb/UsbDevice.java
public class UsbDevice implements Parcelable {
private final Parcelable[] mInterfaces;
/**
* Returns the {@link UsbInterface} at the given index.
*
* @return the interface
*/
public UsbInterface getInterface(int index) {
return (UsbInterface)mInterfaces[index];
}
}
之后,就是如何使用UsbDevice类了。
USB设备属于热插拔设备,一旦系统监测到其热插拔时间,会有相应事件上报:
frameworks/base/core/java/android/hardware/usb/UsbManager.java
/**
* This intent is sent when a USB device is attached to the USB bus when in host mode.
*/
public static final String ACTION_USB_DEVICE_ATTACHED =
"android.hardware.usb.action.USB_DEVICE_ATTACHED";
/**
* This intent is sent when a USB device is detached from the USB bus when in host mode.
*/
public static final String ACTION_USB_DEVICE_DETACHED =
"android.hardware.usb.action.USB_DEVICE_DETACHED";
所以,注册监听事件的广播即可,如:
class UsbDeviceEventReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
UsbDevice device = (UsbDevice)intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
}
}
mReceiver = new UsbDeviceEventReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(mReceiver, filter);
六、结束
Android流程:driver->JNI->Framework->APP,几乎所有模块都是这个模式,对于一个外设,如果这几个部分都清楚的话心里会特别明亮。
这个地方借鉴了https://blog.csdn.net/u013686019/article/details/50409421/这的内容。