關於USB類型的常識整理

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

Use class information in the Interface Descriptors

01h

Interface

Audio

02h

Both

Communications and CDC Control

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

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/這的內容。

發佈了71 篇原創文章 · 獲贊 31 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章