WebUSB API与Serial API的USB设备兼容性技术问询
Understanding USB Device Compatibility with WebUSB vs. Serial API
Hey there! Let’s dive into your questions about WebUSB and Serial API compatibility, using the device details you shared to make this super concrete.
1. What factors determine whether a USB device works with Serial API or WebUSB?
The core factors boil down to how the device identifies itself via USB descriptors and whether the operating system maps it to a serial port:
- Serial API targets devices that the OS recognizes as serial ports: This includes two main types:
- USB-to-serial chips (like your FTDI "USB <-> Serial" device) where the OS has a built-in driver that translates USB traffic to a virtual serial port.
- USB CDC (Communication Device Class) devices that implement the CDC ACM (Abstract Control Model) subclass, which standardizes serial-over-USB communication.
Looking at yourioregoutput, the Serial-compatible FTDI device hasbDeviceClass=0(a "vendor-specific" class), but OS X’s built-in FTDI driver still maps it to a serial port—hence it shows up in the Serial API picker.
- WebUSB targets devices not claimed by the OS’s built-in drivers: This includes devices that either:
- Use a custom USB class/subclass that the OS doesn’t have a driver for (like your EMIT eScan device with
bDeviceClass=2—which is the USB Communication class, but OS X doesn’t have a built-in driver for its specific implementation). - Explicitly include WebUSB-specific descriptors (like the Microsoft OS 2.0 descriptor) that tell the OS to allow browser access even if a driver exists.
- Use a custom USB class/subclass that the OS doesn’t have a driver for (like your EMIT eScan device with
2. Does compatibility depend on computer drivers, and is it related to USB CDC and its drivers?
Absolutely—drivers are the biggest factor here:
- For Serial API to work, the OS needs a driver that translates the device’s USB communication into a virtual serial port. For USB CDC devices, this usually means a CDC ACM driver (many OSes include this by default for standard CDC devices). For USB-to-serial chips (like FTDI, Prolific), the OS needs a chip-specific driver.
- If no such driver exists (or it’s not installed), the OS won’t map the device to a serial port. That’s when WebUSB becomes an option—since it lets browsers communicate directly with the USB device without relying on a system driver.
Your EMIT device is a perfect example: it’s in the USB Communication class (bDeviceClass=2), but OS X doesn’t have a built-in driver for its particular flavor, so it doesn’t show up in Serial API and is accessible via WebUSB.
3. Can the same device work with WebUSB on one computer and Serial API on another?
100% yes—this is all about driver and OS differences:
- For example, a custom USB CDC device might work with Serial API on Windows (if you install the vendor’s CDC driver) but only with WebUSB on a Linux distro that doesn’t include a compatible CDC driver.
- Even across versions of the same OS: an older OS might lack a driver for a newer USB-to-serial chip, so WebUSB is your only option, while a newer OS with the built-in driver would let you use Serial API.
4. If writing a native C program, can I choose between serial communication or direct USB protocol?
It depends on the device’s hardware design:
- If the device uses a USB-to-serial chip (like your FTDI device): Yes, you have both options. You can either:
- Use standard serial port APIs (like POSIX
termioson OS X/Linux, orCreateFileon Windows) to talk to the virtual serial port created by the driver. - Use a USB library like
libusbto communicate directly with the USB chip, bypassing the serial driver entirely.
- Use standard serial port APIs (like POSIX
- If the device is a custom USB device (like your EMIT device): You’ll only be able to use direct USB protocol (via
libusbor similar) unless the vendor provides a driver that maps it to a virtual serial port. If such a driver exists, you could then use serial APIs instead.
Quick note on your data loss issue
You mentioned that Serial API works without data loss using Streams, but WebUSB batch transfers lose data if you don’t pull it fast enough. That’s because:
- Serial API relies on the OS’s serial driver, which handles buffering incoming data for you—so even if your code is a bit slow, the driver holds onto data until you read it.
- WebUSB requires your code to handle buffering directly. If your device’s internal buffer fills up before you read the data via WebUSB, it’ll drop new data. To fix this, try optimizing your read loop to run more frequently, or check if the device has settings to increase its internal buffer size.
Your Device ioreg Outputs
Serial API Compatible Device (FTDI):
+-o USB <-> Serial@14200000 <class AppleUSBDevice, id 0x10000d0b3, registered, matched, active, busy 0 (10 ms), retain 28> { "sessionID" = 210143274448224 "iManufacturer" = 1 "bNumConfigurations" = 1 "idProduct" = 24577 "bcdDevice" = 1024 "Bus Power Available" = 250 "USB Address" = 30 "bMaxPacketSize0" = 8 "iProduct" = 2 "iSerialNumber" = 0 "bDeviceClass" = 0 "Built-In" = No "locationID" = 337641472 "bDeviceSubClass" = 0 "bcdUSB" = 272 "USB Product Name" = "USB <-> Serial" "PortNum" = 1 "non-removable" = "no" "IOCFPlugInTypes" = {"9dc7b780-9ec0-11d4-a54f-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"} "bDeviceProtocol" = 0 "IOUserClientClass" = "IOUSBDeviceUserClientV2" "IOPowerManagement" = {"DevicePowerState"=0,"CurrentPowerState"=4,"CapabilityFlags"=32768,"MaxPowerState"=4,"DriverPowerState"=4} "IOBusyInterest" = "IOCommand is not serializable" "Device Speed" = 1 "USB Vendor Name" = "FTDI" "idVendor" = 1027 "kUSBCurrentConfiguration" = 1 "IOGeneralInterest" = "IOCommand is not serializable" "IOClassNameOverride" = "IOUSBDevice" }
WebUSB Compatible Device (EMIT):
+-o Emit eScan@14200000 <class AppleUSBDevice, id 0x10000d0d8, registered, matched, active, busy 0 (10 ms), retain 23> { "sessionID" = 210198267509902 "iManufacturer" = 1 "bNumConfigurations" = 1 "idProduct" = 768 "bcdDevice" = 274 "Bus Power Available" = 250 "USB Address" = 31 "bMaxPacketSize0" = 8 "iProduct" = 2 "iSerialNumber" = 3 "bDeviceClass" = 2 "Built-In" = No "locationID" = 337641472 "bDeviceSubClass" = 0 "bcdUSB" = 512 "USB Product Name" = "Emit eScan" "PortNum" = 2 "non-removable" = "no" "IOCFPlugInTypes" = {"9dc7b780-9ec0-11d4-a54f-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"} "bDeviceProtocol" = 0 "IOUserClientClass" = "IOUSBDeviceUserClientV2" "IOPowerManagement" = {"DevicePowerState"=0,"CurrentPowerState"=4,"CapabilityFlags"=32768,"MaxPowerState"=4,"DriverPowerState"=4} "IOBusyInterest" = "IOCommand is not serializable" "Device Speed" = 1 "USB Vendor Name" = "EMIT AS" "idVendor" = 8263 "kUSBCurrentConfiguration" = 1 "IOGeneralInterest" = "IOCommand is not serializable" "USB Serial Number" = "0969395112001500" "IOClassNameOverride" = "IOUSBDevice" }
内容的提问来源于stack exchange,提问作者Michael Johansen
相关产品推荐
相关产品推荐

