Skip to content

Commit

Permalink
Add quirk for mbed CMSIS-DAP firmware when filtering by bDeviceClass.
Browse files Browse the repository at this point in the history
- This fixes pyocd#588. Old "Mbed CMSIS-DAP" firmware has an incorrect device
  class value, so it was being filtered out. This problem only occurred
  on Linux.
- Added a common filter_device_by_class() function that checks the
  bDeviceClass value and also applies any quirks.
- Renamed filter_device() to filter_device_by_usage_page().
  • Loading branch information
flit committed Mar 21, 2019
1 parent e7d8971 commit 044a13e
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 13 deletions.
34 changes: 29 additions & 5 deletions pyocd/probe/pydapaccess/interface/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.

# USB class codes.
USB_CLASS_COMPOSITE = 0x00
USB_CLASS_COMMUNICATIONS = 0x02
USB_CLASS_MISCELLANEOUS = 0xef

CMSIS_DAP_USB_CLASSES = [
Expand All @@ -25,14 +27,36 @@
NXP_VID = 0x1fc9
NXP_LPCLINK2_PID = 0x0090

ARM_VID = 0x0d28
DAPLINK_PID = 0x0204

CMSIS_DAP_HID_USAGE_PAGE = 0xff00

def filter_device(vid, pid, usage_page):
"""! @brief Test whether the device should be ignored.
def filter_device_by_class(vid, pid, device_class):
"""! @brief Test whether the device should be ignored by comparing bDeviceClass.
This function checks the device's bDeviceClass to determine whether the it is likely to be
a CMSIS-DAP device. It uses the vid and pid for device-specific quirks.
@retval True Skip the device.
@retval False The device is valid.
"""
# Check valid classes for CMSIS-DAP firmware.
if device_class in CMSIS_DAP_USB_CLASSES:
return False
# Old "Mbed CMSIS-DAP" firmware has an incorrect bDeviceClass.
if (vid == ARM_VID) and (pid == DAPLINK_PID) and (device_class == USB_CLASS_COMMUNICATIONS):
return False
# Any other class indicates the device is not CMSIS-DAP.
return True

def filter_device_by_usage_page(vid, pid, usage_page):
"""! @brief Test whether the device should be ignored by comparing the HID usage page.
This function performs device-specific tests to determine whether the device is
a CMSIS-DAP interface. An example is the NXP LPC-Link2, which has extra HID interfaces
with usage pages other than 0xff00.
This function performs device-specific tests to determine whether the device is a CMSIS-DAP
interface. The only current test is for the NXP LPC-Link2, which has extra HID interfaces with
usage pages other than 0xff00. No generic tests are done regardless of VID/PID, because it is
not clear whether all CMSIS-DAP devices have the usage page set to the same value.
@retval True Skip the device.
@retval False The device is valid.
Expand Down
4 changes: 2 additions & 2 deletions pyocd/probe/pydapaccess/interface/hidapi_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# limitations under the License.

from .interface import Interface
from .common import filter_device
from .common import filter_device_by_usage_page
from ..dap_access_api import DAPAccessIntf
from ....utility.compatibility import to_str_safe
import logging
Expand Down Expand Up @@ -78,7 +78,7 @@ def get_all_connected_interfaces():
pid = deviceInfo['product_id']

# Perform device-specific filtering.
if filter_device(vid, pid, deviceInfo['usage_page']):
if filter_device_by_usage_page(vid, pid, deviceInfo['usage_page']):
continue

try:
Expand Down
4 changes: 2 additions & 2 deletions pyocd/probe/pydapaccess/interface/pyusb_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# limitations under the License.

from .interface import Interface
from .common import CMSIS_DAP_USB_CLASSES
from .common import filter_device_by_class
from ..dap_access_api import DAPAccessIntf
import logging
import os
Expand Down Expand Up @@ -257,7 +257,7 @@ def __init__(self, serial=None):
def __call__(self, dev):
"""Return True if this is a DAP device, False otherwise"""
# Check if the device class is a valid one for CMSIS-DAP.
if dev.bDeviceClass not in CMSIS_DAP_USB_CLASSES:
if filter_device_by_class(dev.idVendor, dev.idProduct, dev.bDeviceClass):
return False

try:
Expand Down
4 changes: 2 additions & 2 deletions pyocd/probe/pydapaccess/interface/pyusb_v2_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# limitations under the License.

from .interface import Interface
from .common import CMSIS_DAP_USB_CLASSES
from .common import filter_device_by_class
from ..dap_access_api import DAPAccessIntf
from ... import common
import logging
Expand Down Expand Up @@ -266,7 +266,7 @@ def __init__(self, serial=None):
def __call__(self, dev):
"""! @brief Return True if this is a CMSIS-DAPv2 device, False otherwise"""
# Check if the device class is a valid one for CMSIS-DAP.
if dev.bDeviceClass not in CMSIS_DAP_USB_CLASSES:
if filter_device_by_class(dev.idVendor, dev.idProduct, dev.bDeviceClass):
return False

try:
Expand Down
4 changes: 2 additions & 2 deletions pyocd/probe/pydapaccess/interface/pywinusb_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
# limitations under the License.

from .interface import Interface
from .common import filter_device
from .common import filter_device_by_usage_page
from ..dap_access_api import DAPAccessIntf
from ....utility.timeout import Timeout
import logging
Expand Down Expand Up @@ -114,7 +114,7 @@ def get_all_connected_interfaces():
dev.open(shared=True)

# Perform device-specific filtering.
if filter_device(dev.vendor_id, dev.product_id, dev.hid_caps.usage_page):
if filter_device_by_usage_page(dev.vendor_id, dev.product_id, dev.hid_caps.usage_page):
dev.close()
continue

Expand Down

0 comments on commit 044a13e

Please sign in to comment.