Port and device detection

How ModemManager detects ports and devices

Udev

The ModemManager daemon does not attempt to detect by itself which modems are available in the system. It instead relies on the udevd daemon and the port addition and removal events produced whenever the port states change in the kernel.

ModemManager also uses an explicit query on udev during bootup in order to know which ports were detected and exposed before the daemon was ready to receive new addition and removal events.

Only per-port events are monitored; i.e. explicit port addition and removals. Other events associated with the modem device, like full device addition or removal notifications or per-interface notifications (in USB devices for example) are ignored. On a new device detection, this logic will therefore receive one addition event for each port exposed by the modem.

The ModemManager device detection procedure keeps some timeouts in place so that the logic stops waiting for more ports to be notified after some time. This logic assumes that new port additions in a given device happen in a timely manner, which is the most usual case; if for any reason one of the ports ends up being notified much later than the others, the port may end up fully ignored.

Monitored subsystems

Each plugin in ModemManager registers a list of subsystems it is interested in monitoring. When the available plugins are loaded, the daemon will therefore compile a list of all subsystems that the registered plugins are requesting.

The subsystems usually monitored are:

  • tty subsystem: where all serial ports are exposed (e.g. ttyS0, ttyUSB0, ttyACM0, ttyHS0…).
  • usbmisc subsystem: where the cdc-wdm ports (either QMI, MBIM or AT) are exposed.
  • net subsystem: where all the network ports are exposed.
  • wwan subsystem: where all control ports for PCIe devices and some Qualcomm SoCs are exposed. This subsystem also exposes control ports for QMI and MBIM USB devices, in addition to the original cdc-wdm ports in the usbmisc subsystem, but these are considered duplicates and ignored by ModemManager.
  • qrtr subsystem: This is not a real device subsystem in the kernel, but ModemManager uses this to reference modem management nodes exposed in the Qualcomm specific QRTR bus. Given that these nodes don’t have any exposure in sysfs, there is no way to bind udev tags to them.

udev tags

The tags in udev have several different primary purposes, but in general they can be seen as a way ModemManager uses to configure device specific behaviors.

ModemManager ships and documents several generic udev tags that can be applied to any type of device, and several plugin-specific tags that are meaningful to a set of devices or to a specific manufacturer. The generic udev tags are included and explained in the ModemManager API documentation.

Generic candidate ports and grouping rules

These are rules that allow ModemManager to identify which devices should be detected and probed as possible cellular devices.

Generic port or device ignoring rules

These are rules that allow the user to deny access to certain ports on a given device, or to full devices.

Generic port type hint rules

These are rules that allow the probing logic of ModemManager to decide faster what kind of protocol is expected in a given port, as well as specifying behavior that is expected in that port (e.g. in AT ports there may be one port that is targeted to be used for PPP and not for general control).

Generic RS232 port configuration rules

Plugin-specific device identification rules

Certain modems, like the Ericsson MBM modules, require explicit tags to identify them as being modems that can be controlled by ModemManager. This is usually required with manufacturers that ship many types of different devices under the same USB or PCI vendor identification.

Feature configuration/disabling rules

There are cases where some specific features are non-functional in a given device, or even worse, they may end up triggering irrecoverable firmware crashes. When they are identified, feature specific udev tags are set in the relevant modem ports so that ModemManager knows it should avoid using that feature. Notable examples include the AT^NDISDUP support in Huawei devices or the AT+CPOL based management in multiple plugins.

Adding new udev tags

Users can specify udev tags themselves, by creating new rules files that are installed (usually) under /lib/udev/rules.d. There aren’t many requirements to this user rules files, but the existing ones are important:

  • The rules file names should be prefixed by either 78-mm- or 79-mm-. This is so that the user-defined rules are processed after the generic rules (which are all installed as 77-mm-) and before the candidate rules (in the 80-mm- prefixed rules file).
  • Even though official udev rules allow running multiple actions matching a set of rules, the ModemManager udev rules always process one single action on every line. This is a limitation of the custom udev rule parser used in openwrt.
  • Following the same pattern as the ModemManager udev rules, the rules should be run on add, change, move and bind ACTIONs.
  • Port specific tags should be applied to specific ports (e.g. USB ports identified by the USB interface number).
  • Device specific tags should be applied to all control ports in the same way or to the full device if there is one in the sysfs tree.
  • Beware of SUBSYSTEMS vs SUBSYSTEM, or ATTRS vs ATTR and so on. One (without the trailing S) matches a specific device in the device hierarchy, while the other (with the trailing S) matches a device and all its parents on the hierarchy. For example, a TTY port in a USB device will definitely match SUBSYSTEMS==”usb” (because a direct parent of the TTY port will be the physical USB device) but it will also match SUBSYSTEMS==”pci” (because the USB controller where the device is managed is hanging off the PCI bus).
  • Writing udev rules is tricky, so following what the existing rules do is always a good approach.

A new set of rules specified by a user could look like this:

$ cat /lib/udev/rules.d/78-mm-my-rules.rules
ACTION!="add|change|move|bind", GOTO="mm_my_rules_end"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1234", GOTO="mm_my_rules"
GOTO="mm_my_rules_end"

LABEL="mm_my_rules"
# Store interface number in an env var
SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", \
  ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}"
# USB iface #0 will be primary AT port
ATTRS{idVendor}=="1234", ATTRS{idProduct}=="abcd", ENV{.MM_USBIFNUM}=="00", \
  SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
# USB iface #1 will be PPP port
ATTRS{idVendor}=="1234", ATTRS{idProduct}=="abcd", ENV{.MM_USBIFNUM}=="01", \
  SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PPP}="1"
LABEL="mm_my_rules_end"

Once the new file in the filesystem is created, validating whether the tags are correctly applied would involve two steps:

  • First, reloading and applying the rules:
$ sudo udevadm control –reload
$ sudo udevadm trigger
  • Second, showing which tags are available in the target port:
$ sudo udevadm info -p /sys/class/tty/ttyUSB0

Hotplug in Openwrt

There is no udev in openwrt, so ModemManager has an alternative way to get notified of the port addition and removal events. In this operating system, the ModemManager package installs a set of hotplug scripts that are called by the openwrt init system whenever port state changes happen in the kernel. As in the case of udev, ModemManager processes per-port events and determines at runtime which ports should be aggregated into the same modem object.

During ModemManager bootup, the init script in openwrt will ensure that all the port addition and removal events that happened before the daemon was ready to process them are properly queued up so that they get processed in the same order as they originally happened.

There is also no udev rules processing in openwrt, and so ModemManager does its own processing of the rules in a way that should be mostly equivalent to how udev processes them. The built-in udev processor in ModemManager is not as complete as the original one, so adding custom rules may not always work, unless the new rules are equivalent to other existing ones and therefore implicitly supported.

Port selection filters in ModemManager

The ModemManager daemon will not probe all possible control ports it finds, as doing so would break a lot of non-modem ports that devices expose as TTYs. But this was not the default behavior in older releases, and the ModemManager daemon would end up poking serial ports at will while breaking the communication attempted by the real user processes of those serial ports. Users reported issues where the daemon poked Arduino serial ports, GPS devices, or even screen readers for the visually impaired. A lot of effort was put into improving this situation, which led to a series of changes during several years to reach the state we have now.

  • Until release 1.8.0, the default behavior of ModemManager was to by default attempt to probe TTY ports unless they were deny-listed explicitly. The project would maintain a large list of udev rules identifying devices that are not modems but still exposed TTYs, but (no surprise) keeping that list up to date was a mess and very error prone.
  • In release 1.8.0, a new set of filter types was introduced:
    • The old behavior, where ports were probed unless explicitly flagged with a specific udev tag, was still the default one and the filter was named “default”. With this filter, platform serial ports (e.g. real RS232 physical ports in the system) could be automatically probed if a manual scan operation was triggered.
    • “whitelist-only” filter, in which ModemManager would only probe control ports if they were explicitly flagged with the ID_MM_DEVICE_PROCESS udev tag.
    • “strict” , in which ModemManager would by default not probe the TTY ports unless it knew with a high amount of certainty that the port was a modem port; e.g. with rules checking for AT protocol support definitions in ttyACM ports, looking at which kernel drivers are in use, or even based on port type hint rules already defined in ModemManager. The option to request a manual scan was also removed when this filter was used. Platform RS232 ports need to be explicitly flagged (e.g. with ID_MM_DEVICE_PROCESS) to be probed.
    • “paranoid” filter was equal to the “strict” mode but also applied the list of denied devices that the “default” filter was based on.
  • In release 1.14.0, ModemManager would switch to use the “strict” filter by default if no other one was explicitly selected. The old “default” filter was renamed to “legacy” and considered deprecated.
  • In release 1.18.0 the “legacy” and “paranoid” filter types were fully removed, along with all the lists of udev rules for denied devices.
  • In release 1.20.0 the “whitelist-only” filter was renamed to “allowlist-only”, while deprecating the older name.

Since 1.20.0 only the “strict” and “allowlist-only” filter types are used, defaulting to “strict” if none is explicitly selected. These filters will be mapped to more detailed rules applied by ModemManager upon device detection.

E.g. when the “strict” filter is selected, all the heuristics to detect cellular device ports are enabled, as seen in the daemon debug logs:

[filter] created
[filter]   explicit allowlist:         yes
[filter]   explicit blocklist:         yes
[filter]   plugin allowlist:           yes
[filter]   qrtr devices allowed:       yes
[filter]   virtual devices forbidden:  yes
[filter]   net devices allowed:        yes
[filter]   usbmisc devices allowed:    yes
[filter]   rpmsg devices allowed:      yes
[filter]   wwan devices allowed:       yes
[filter]   tty devices:
[filter]       platform driver check:    yes
[filter]       driver check:             yes
[filter]       cdc-acm interface check:  yes
[filter]       with net check:           yes
[filter]       default:                  forbidden

When the “allowlist-only” filter is selected, the amount of rules enabled is limited to only one, the explicit allowlist:

[filter] created
[filter]   explicit allowlist:         yes
[filter]   explicit blocklist:         no
[filter]   plugin allowlist:           no
[filter]   qrtr devices allowed:       no
[filter]   virtual devices forbidden:  no
[filter]   net devices allowed:        no
[filter]   usbmisc devices allowed:    no
[filter]   rpmsg devices allowed:      no
[filter]   wwan devices allowed:       no
[filter]   tty devices:                no

Worth noting, ModemManager does not touch the network ports of a modem in any way. During the daemon startup there isn’t a strict list of rules to decide whether a network port is part of a modem device or not, the network ports are seen as additional ports in a modem if other control ports are found and validated.

Example device detection logs

The following log shows the device detection phase of a device during ModemManager bootup, with comments about what is happening at each moment.

// ttyUSB0 is detected via udev, a set of port identification
// parameters are preloaded.
[34.337] [ttyUSB0] port contents loaded:
[34.338] [ttyUSB0]   bus: usb
[34.339] [ttyUSB0]   interface: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.2
[34.340] [ttyUSB0]   device: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1
[34.340] [ttyUSB0]   driver: qcserial
[34.341] [ttyUSB0]   vendor: 1199
[34.341] [ttyUSB0]   product: 9091
[34.342] [ttyUSB0]   revision: 0006
[34.343] [base-manager] adding port ttyUSB0 at sysfs path: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.2/ttyUSB0/tty/ttyUSB0

// The currently active filter flags the port as allowed and specifies
// why. In this case, the specific vid (1199) is allowlisted by the
// Sierra plugin.
[34.359] [filter] (tty/ttyUSB0) port allowed: device is allowlisted by plugin (vid)

// ttyUSB0 is the first port detected in the modem device.
[34.360] [base-manager] port ttyUSB0 is first in device /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1

// A new support task is created for the device, which will determine
// which plugin takes care of managing it. In this case, the task is
// not yet launched because there is a “minimum wait time” that
// ModemManager waits before starting the probing tasks (a few
// seconds).
[34.373] [plugin-manager] task 0: new support task for device: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1
[34.391] [plugin-manager] task 0: port grabbed: ttyUSB0
[34.393] [plugin-manager] task 0,ttyUSB0: new support task for port
[34.393] [plugin-manager] task 0,ttyUSB0: deferred until min wait time elapsed

// ttyUSB1 is detected via udev, a set of port identification
// parameters are preloaded.
[34.398] [ttyUSB1] port contents loaded:
[34.398] [ttyUSB1]   bus: usb
[34.398] [ttyUSB1]   interface: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.3
[34.398] [ttyUSB1]   device: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1
[34.399] [ttyUSB1]   driver: qcserial
[34.399] [ttyUSB1]   vendor: 1199
[34.399] [ttyUSB1]   product: 9091
[34.399] [ttyUSB1]   revision: 0006
[34.399] [base-manager] adding port ttyUSB1 at sysfs path: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.3/ttyUSB1/tty/ttyUSB1
[34.402] [filter] (tty/ttyUSB1) port allowed: device is allowlisted by plugin (vid)

// ttyUSB1 is added as an additional port to the already existing
// device.
[34.404] [base-manager] additional port ttyUSB1 in device /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1

// The support task is notified about the new ttyUSB1 port, but still
// deferred.
[34.405] [plugin-manager] task 0: port grabbed: ttyUSB1
[34.407] [plugin-manager] task 0,ttyUSB1: new support task for port
[34.407] [plugin-manager] task 0,ttyUSB1: deferred until min wait time elapsed

// wwan0 net port is detected via udev, a set of port identification
// parameters are preloaded.
[34.779] [wwan0] port contents loaded:
[34.779] [wwan0]   bus: usb
[34.779] [wwan0]   interface: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.0
[34.779] [wwan0]   device: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1
[34.779] [wwan0]   driver: cdc_mbim
[34.780] [wwan0]   vendor: 1199
[34.780] [wwan0]   product: 9091
[34.780] [wwan0]   revision: 0006
[34.780] [base-manager] adding port wwan0 at sysfs path: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.0/net/wwan0
[34.782] [filter] (net/wwan0) port allowed: device is allowlisted by plugin (vid)
[34.783] [base-manager] additional port wwan0 in device /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1

// The support task is notified about the new wwan0 port, but still
// deferred.
[34.784] [plugin-manager] task 0: port grabbed: wwan0
[34.784] [plugin-manager] task 0,wwan0: new support task for port
[34.785] [plugin-manager] task 0,wwan0: deferred until min wait time elapsed

// cdc-wdm2 net port is detected via udev, a set of port
// identification parameters are preloaded.
[34.817] [cdc-wdm2] port contents loaded:
[34.817] [cdc-wdm2]   bus: usb
[34.817] [cdc-wdm2]   interface: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.0
[34.817] [cdc-wdm2]   device: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1
[34.817] [cdc-wdm2]   driver: cdc_mbim
[34.817] [cdc-wdm2]   vendor: 1199
[34.818] [cdc-wdm2]   product: 9091
[34.818] [cdc-wdm2]   revision: 0006
[34.818] [base-manager] adding port cdc-wdm2 at sysfs path: /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1/2-4.1.1:1.0/usbmisc/cdc-wdm2
[34.819] [filter] (usbmisc/cdc-wdm2) port allowed: device is allowlisted by plugin (vid)
[34.819] [base-manager] additional port cdc-wdm2 in device /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1

// The support task is notified about the new cdc-wdm2 port, but still
// deferred.
[34.820] [plugin-manager] task 0: port grabbed: cdc-wdm2
[34.820] [plugin-manager] task 0,cdc-wdm2: new support task for port
[34.820] [plugin-manager] task 0,cdc-wdm2: deferred until min wait time elapsed

// Once the “minimum wait time” elapses, the support task launches
// per-port checks to decide which plugin should manage the device.
[35.878] [plugin-manager] task 0: min wait time elapsed

// In this case, cdc-wdm2 is the first port that gets checked. The
// logic will go over all existing plugins to decide which ones can
// manage the port. Initially, the logs will include messages for all
// the plugins that cannot manage the port and why.
[35.885] [plugin/tp-link] port cdc-wdm2 filtered by implicit MBIM driver
[35.887] [plugin/simtech] port cdc-wdm2 filtered by implicit MBIM driver
[35.887] [plugin/via] port cdc-wdm2 filtered by subsystem
...
[35.896] [plugin/x22x] port cdc-wdm2 filtered by implicit MBIM driver
[35.896] [plugin/u-blox] port cdc-wdm2 filtered by subsystem

// Once all plugins have been checked, a list of possible plugins is
// built and each plugin is then asked to probe each port.
[35.899] [plugin-manager] task 0,cdc-wdm2: found '2' plugins to try
[35.900] [plugin-manager] task 0,cdc-wdm2: will try with plugin 'sierra'
[35.900] [plugin-manager] task 0,cdc-wdm2: will try with plugin 'generic'
[35.901] [plugin-manager] task 0,cdc-wdm2: started
[35.901] [plugin-manager] task 0,cdc-wdm2: checking with plugin 'sierra'

// The list of probe types required is decided per port type. For a
// MBIM device, only checking MBIM capabilities is enough.
[35.906] [plugin/sierra] probes required for port cdc-wdm2: 'mbim'
[35.908] [cdc-wdm2/probe] launching port probing: 'mbim'

// The next port to be checked is wwan0, again it goes through all the
// different available plugins.
[35.910] [plugin/tp-link] port wwan0 filtered by implicit MBIM driver
[35.910] [plugin/simtech] port wwan0 filtered by implicit MBIM driver

[35.915] [plugin/x22x] port wwan0 filtered by implicit MBIM driver
[35.915] [plugin/u-blox] port wwan0 filtered by implicit MBIM driver

// And the list of possible plugins is built for the wwan0 port.
[35.915] [plugin-manager] task 0,wwan0: found '2' plugins to try
[35.915] [plugin-manager] task 0,wwan0: will try with plugin 'sierra'
[35.915] [plugin-manager] task 0,wwan0: will try with plugin 'generic'
[35.915] [plugin-manager] task 0,wwan0: started
[35.915] [plugin-manager] task 0,wwan0: checking with plugin 'sierra'

// The probing of network ports does absolutely nothing, the operation
// will just be deferred until some other port suggests a plugin to be
// selected.
[35.917] [plugin/sierra] probing of port wwan0 deferred until result suggested

// The next port to be checked is ttyUSB1, again it goes through all
// the different available plugins.
[35.917] [plugin/tp-link] port ttyUSB1 filtered by implicit MBIM driver
[35.917] [plugin/simtech] port ttyUSB1 filtered by implicit MBIM driver

[35.921] [plugin/x22x] port ttyUSB1 filtered by implicit MBIM driver
[35.921] [plugin/u-blox] port ttyUSB1 filtered by implicit MBIM driver

// And the list of possible plugins is built for the ttyUSB1 port.
[35.922] [plugin-manager] task 0,ttyUSB1: found '2' plugins to try
[35.922] [plugin-manager] task 0,ttyUSB1: will try with plugin 'sierra'
[35.922] [plugin-manager] task 0,ttyUSB1: will try with plugin 'generic'
[35.922] [plugin-manager] task 0,ttyUSB1: started
[35.922] [plugin-manager] task 0,ttyUSB1: checking with plugin 'sierra'

// For the ttyUSB1 port we need to check different things that the
// plugin requires, it needs to know whether its AT or QCDM, and if
// it’s AT, whether it supports Intel specific XMM operations.
[35.925] [plugin/sierra] probes required for port ttyUSB1: 'at, at-xmm, qcdm'

// The port is known to be possibly AT because it’s flagged with a
// udev tag as a primary or secondary AT port, so all non-AT related
// probes are removed.
[35.925] [ttyUSB1/probe] no QCDM/QMI/MBIM probing in possible AT port
[35.926] [ttyUSB1/probe] port is not QCDM-capable
[35.926] [ttyUSB1/probe] port is not QMI-capable
[35.927] [ttyUSB1/probe] port is not MBIM-capable
[35.927] [ttyUSB1/probe] launching port probing: 'at, at-xmm'

// The next port to be checked is ttyUSB0, again it goes through all
// the different available plugins.
[35.928] [plugin/tp-link] port ttyUSB0 filtered by implicit MBIM driver
[35.928] [plugin/simtech] port ttyUSB0 filtered by implicit MBIM driver

[35.932] [plugin-manager] task 0,ttyUSB0: found '2' plugins to try
[35.932] [plugin-manager] task 0,ttyUSB0: will try with plugin 'sierra'
[35.933] [plugin-manager] task 0,ttyUSB0: will try with plugin 'generic'
[35.933] [plugin-manager] task 0,ttyUSB0: started
[35.933] [plugin-manager] task 0,ttyUSB0: checking with plugin 'sierra'

// As in the ttyUSB1 case, for ttyUSB0 the plugin also requires
// certain probes to be launched.
[35.933] [plugin/sierra] probes required for port ttyUSB0: 'at, at-xmm, qcdm'

// But ttyUSB0 is flagged in udev as being a GPS data port, so all
// probes end up removed, there is nothing to probe in such a port.
[35.934] [ttyUSB0/probe] GPS port detected
[35.934] [ttyUSB0/probe] port is not AT-capable
[35.935] [ttyUSB0/probe] port is not QCDM-capable
[35.935] [ttyUSB0/probe] port is not QMI-capable
[35.935] [ttyUSB0/probe] port is not MBIM-capable
[35.936] [ttyUSB0/probe] port probing finished: no more probings needed

// ttyUSB0 is the first port to finish all its probings, so the result
// of the suggested plugin is forwarded to all the other ports.
[35.938] [plugin-manager] task 0,wwan0: deferring support check until result suggested
[35.941] [plugin-manager] task 0,ttyUSB0: found best plugin for port (sierra)
[35.942] [plugin-manager] task 0,ttyUSB0: finished in '1.549135' seconds
[35.951] [plugin-manager] task 0,ttyUSB0: found best plugin: sierra
[35.954] [plugin-manager] task 0,cdc-wdm2: got suggested plugin (sierra)

// The suggested plugin helps complete the wwan0 port probe task that was
// deferred.
[35.954] [plugin-manager] task 0,wwan0: deferred task completed, got suggested plugin (sierra)
[35.955] [plugin-manager] task 0,ttyUSB1: got suggested plugin (sierra)
[35.957] [plugin-manager] task 0: still 3 running probes (3 active): cdc-wdm2, wwan0, ttyUSB1

// The MBIM probing task in cdc-wdm2 starts.
[35.961] [cdc-wdm2/probe] probing MBIM...

// The AT probing task ttyUSB1 starts. Note that the port type udev
// tag only provides a hint of the protocol that may be supported, the
// daemon still checks for explicit AT protocol support.
[36.036] [ttyUSB1/at] opening serial port...
[36.045] [ttyUSB1/at] setting up baudrate: 57600
[36.048] [ttyUSB1/at] no flow control explicitly requested for device
[36.051] [ttyUSB1/at] port attributes not fully set
[36.055] [ttyUSB1/at] device open count is 1 (open)
[36.058] [plugin-manager] task 0,wwan0: checking with plugin 'sierra'
[36.058] [plugin/sierra] probing of port wwan0 deferred until result suggested
[36.081] [plugin-manager] task 0,wwan0: completed, got suggested plugin (sierra)
[36.081] [plugin-manager] task 0,wwan0: finished in '1.297005' seconds
[36.082] [plugin-manager] task 0,wwan0: best plugin matches device reported one: sierra
[36.083] [plugin-manager] task 0: still 2 running probes (2 active): cdc-wdm2, ttyUSB1

// The MBIM port probing task finishes and reports whether the port is
// MBIM capable.
[36.260] [cdc-wdm2/probe] port is MBIM-capable
[36.262] [/dev/cdc-wdm2] closing device...
[36.286] [plugin-manager] task 0,cdc-wdm2: found best plugin for port (sierra)
[36.286] [plugin-manager] task 0,cdc-wdm2: finished in '1.465742' seconds
[36.286] [plugin-manager] task 0,cdc-wdm2: best plugin matches device reported one: sierra
[36.287] [plugin-manager] task 0: still 1 running probes (1 active): ttyUSB1
[36.321] [plugin-manager] task 0: extra probing time elapsed
[36.321] [plugin-manager] task 0: still 1 running probes (1 active): ttyUSB1
[36.878] [plugin-manager] task 0: min probing time elapsed
[36.879] [plugin-manager] task 0: still 1 running probes (1 active): ttyUSB1

// AT probing in this case completely fails in ttyUSB1, so it is
// flagged as not being AT capable.
[42.778] [ttyUSB1/at] --> 'AT<CR>'
[45.778] [ttyUSB1/at] --> 'AT<CR>'
[48.777] [ttyUSB1/at] --> 'AT<CR>'
[51.776] [ttyUSB1/at] --> 'AT<CR>'
[54.778] [ttyUSB1/probe] port is not AT-capable
[54.780] [plugin-manager] task 0,ttyUSB1: found best plugin for port (sierra)
[54.780] [plugin-manager] task 0,ttyUSB1: finished in '20.373198' seconds
[54.785] [plugin-manager] task 0,ttyUSB1: best plugin matches device reported one: sierra

// The whole device probing sequence takes around 20s in this case,
// mainly due to the AT command timeouts happening in ttyUSB1.
[54.785] [plugin-manager] task 0: no more ports to probe
[54.785] [plugin-manager] task 0: finished in '20.412880' seconds

// The plugin manager ends up creating a new modem object via the
// Sierra plugin.
[54.787] [device /sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1] creating modem with plugin 'sierra' and '4' ports
[54.791] [plugin/sierra] (sierra) MBIM-powered Sierra modem found...
[54.894] [cdc-wdm2/mbim] port monitoring enabled in MBIM port
[54.898] [modem0] port 'usbmisc/cdc-wdm2' grabbed
[54.901] [modem0] port 'net/wwan0' grabbed
[54.902] [plugin/sierra] could not grab port ttyUSB1: Cannot add port 'tty/ttyUSB1', unhandled port type
[54.905] [modem0] port 'tty/ttyUSB0' grabbed
[54.910] [modem0] net/wwan0: net (data)
[54.911] [modem0] tty/ttyUSB0: gps (nmea)
[54.912] [modem0] usbmisc/cdc-wdm2: mbim
[54.938] [base-manager] modem for device '/sys/devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1.1' successfully created