1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter-feeds.git synced 2025-03-09 15:40:03 +00:00

update modemmanager libqmi libmbim

This commit is contained in:
suyuan 2023-11-03 23:35:18 +08:00
parent 6a946aaa66
commit 6ae60f4a55
10 changed files with 183 additions and 96 deletions

View file

@ -8,12 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=libmbim
PKG_SOURCE_VERSION:=1.29.2
PKG_SOURCE_VERSION:=1.30.0
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://gitlab.freedesktop.org/mobile-broadband/libmbim.git
#PKG_MIRROR_HASH:=0b0b46016738fc22355d5a58c8a2d1b2f04906c49c51a50b57a09640d13b00b7
PKG_MIRROR_HASH:=8fc4e2d78d6a1003bf89303d3ce779283b176d74e84a241ba8efb0d468605268
PKG_BUILD_FLAGS:=gc-sections
PKG_MAINTAINER:=Nicholas Smith <nicholas@nbembedded.com>
@ -21,8 +23,7 @@ include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/nls.mk
include $(INCLUDE_DIR)/meson.mk
TARGET_CFLAGS += -ffunction-sections -fdata-sections -fno-merge-all-constants -fmerge-constants
TARGET_LDFLAGS += -Wl,--gc-sections
TARGET_CFLAGS += -fno-merge-all-constants -fmerge-constants
MESON_ARGS += \
-Dintrospection=false \

View file

@ -8,12 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=libqmi
PKG_SOURCE_VERSION:=1.33.3
PKG_SOURCE_VERSION:=1.34.0
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://gitlab.freedesktop.org/mobile-broadband/libqmi.git
#PKG_MIRROR_HASH:=711d16d75a6a9afaefcf2be1bc845a4a6181dff786dfbd079e41e91279a0be91
PKG_MIRROR_HASH:=af3dc760d0c40ef8af1f8b424435daa12bff698ed45b1cc9a9e38ea62ed047f0
PKG_BUILD_FLAGS:=gc-sections
PKG_MAINTAINER:=Nicholas Smith <nicholas@nbembedded.com>
@ -21,8 +23,7 @@ include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/nls.mk
include $(INCLUDE_DIR)/meson.mk
TARGET_CFLAGS += -ffunction-sections -fdata-sections -fno-merge-all-constants -fmerge-constants
TARGET_LDFLAGS += -Wl,--gc-sections
TARGET_CFLAGS += -fno-merge-all-constants -fmerge-constants
define Package/libqmi/config
source "$(SOURCE)/Config.in"

View file

@ -8,12 +8,12 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=modemmanager
PKG_SOURCE_VERSION:=1.20.6
PKG_RELEASE:=8
PKG_SOURCE_VERSION:=1.22.0
PKG_RELEASE:=5
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL:=https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git
PKG_MIRROR_HASH:=e90103e2e42bb826bbbac83937a9a69f50348cd6ce0d8da655a12b65494ce7c9
PKG_MIRROR_HASH:=98daa1a15075c88afb3ed0de20dc83fe51d2ba3c66318ce3f731da4616a2e192
PKG_MAINTAINER:=Nicholas Smith <nicholas@nbembedded.com>
PKG_LICENSE:=GPL-2.0-or-later
@ -64,6 +64,7 @@ MESON_ARGS += \
-Dintrospection=false \
-Dman=false \
-Dbash_completion=false \
-Dbuiltin_plugins=true \
-Db_lto=true \
-Dmbim=$(if $(CONFIG_MODEMMANAGER_WITH_MBIM),true,false) \
-Dqmi=$(if $(CONFIG_MODEMMANAGER_WITH_QMI),true,false) \
@ -80,6 +81,8 @@ define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/ModemManager.pc $(1)/usr/lib/pkgconfig
$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/mm-glib.pc $(1)/usr/lib/pkgconfig
$(INSTALL_DIR) $(1)/usr/share/dbus-1/interfaces
$(CP) $(PKG_BUILD_DIR)/introspection/org.freedesktop.ModemManager1.* $(1)/usr/share/dbus-1/interfaces
endef
define Package/modemmanager/install
@ -96,10 +99,6 @@ define Package/modemmanager/install
$(INSTALL_DIR) $(1)/usr/lib
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libmm-glib.so.* $(1)/usr/lib
$(INSTALL_DIR) $(1)/usr/lib/ModemManager
$(CP) $(PKG_INSTALL_DIR)/usr/lib/ModemManager/libmm-shared-*.so* $(1)/usr/lib/ModemManager
$(CP) $(PKG_INSTALL_DIR)/usr/lib/ModemManager/libmm-plugin-*.so* $(1)/usr/lib/ModemManager
$(INSTALL_DIR) $(1)/usr/lib/ModemManager/connection.d
$(INSTALL_BIN) ./files/10-report-down $(1)/usr/lib/ModemManager/connection.d
@ -110,7 +109,7 @@ define Package/modemmanager/install
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/dbus-1/system-services/org.freedesktop.ModemManager1.service $(1)/usr/share/dbus-1/system-services
$(INSTALL_DIR) $(1)/usr/share/ModemManager
$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/ModemManager/*.conf $(1)/usr/share/ModemManager
$$(if $$(wildcard $(PKG_INSTALL_DIR)/usr/share/ModemManager/*.conf),$(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/share/ModemManager/*.conf $(1)/usr/share/ModemManager,)
$(INSTALL_DATA) ./files/modemmanager.common $(1)/usr/share/ModemManager
$(INSTALL_DIR) $(1)/usr/share/ModemManager/fcc-unlock.available.d

View file

@ -22,8 +22,10 @@ Once installed, you can configure the 2G/3G/4G modem connections directly in
option password 'vodafone'
option pincode '7423'
option iptype 'ipv4'
option plmn '214001'
option lowpower '1'
option signalrate '30'
option allow_roaming '1'
Only 'device' and 'proto' are mandatory options, the remaining ones are all
optional.
@ -36,5 +38,7 @@ allowing all protocols.
The 'iptype' option supports any of these values: 'ipv4', 'ipv6' or 'ipv4v6'.
It will default to 'ipv4' if not given.
The 'plmn' option allows to set the network operator MCCMNC.
The 'signalrate' option set's the signal refresh rate (in seconds) for the device.
You can call signal info with command: mmcli -m 0 --signal-get

11
modemmanager/files/10-report-down Normal file → Executable file
View file

@ -29,7 +29,12 @@ MODEM_DEVICE=$(modemmanager_get_field "${MODEM_STATUS}" "modem.generic.device")
CFG=$(mm_get_modem_config "${MODEM_DEVICE}")
[ -n "${CFG}" ] || exit 3
logger -t "modemmanager" "interface ${CFG} (network device ${INTERFACE}) ${STATE}"
proto_init_update $INTERFACE 0
proto_send_update $CFG
IFUP=$(ifstatus "${CFG}" | jsonfilter -e "@.up")
[ "${IFUP}" = "true" ] && {
logger -t "modemmanager" "interface ${CFG} (network device ${INTERFACE}) ${STATE}"
proto_init_update $INTERFACE 0
proto_send_update $CFG
}
exit 0

View file

@ -6,6 +6,7 @@
. /lib/functions.sh
. /lib/netifd/netifd-proto.sh
INCLUDE_ONLY=1 . /lib/netifd/proto/modemmanager.sh
################################################################################
# Runtime state
@ -20,7 +21,8 @@ MODEMMANAGER_EVENTS_CACHE="${MODEMMANAGER_RUNDIR}/events.cache"
# Common logging
mm_log() {
[ "$(uci -q get openmptcprouter.settings.debug)" = "true" ] && logger -t "ModemManager" "hotplug: $*"
local level="$1"; shift
logger -p "daemon.${level}" -t "ModemManager[$$]" "hotplug: $*"
}
################################################################################
@ -39,14 +41,14 @@ mm_find_physdev_sysfs_path() {
# avoid infinite loops iterating
[ -z "${tmp_path}" ] || [ "${tmp_path}" = "/" ] && return
# for USB devices, the physical device will be that with a idVendor
# and idProduct pair of files
# For USB devices, the physical device will be that with a idVendor
# and idProduct pair of files
[ -f "${tmp_path}"/idVendor ] && [ -f "${tmp_path}"/idProduct ] && {
tmp_path=$(readlink -f "$tmp_path")
echo "${tmp_path}"
return
}
# For PCI devices, the physical device will be that with a vendor
# and device pair of files
[ -f "${tmp_path}"/vendor ] && [ -f "${tmp_path}"/device ] && {
@ -138,10 +140,6 @@ mm_get_modem_config_foreach_cb() {
local cfg="$1"
local sysfspath="$2"
local proto
config_get proto "${cfg}" proto
[ "${proto}" = modemmanager ] || return 0
local dev
dev=$(uci_get network "${cfg}" device)
[ "${dev}" = "${sysfspath}" ] || return 0
@ -169,7 +167,7 @@ mm_wait_for_modem() {
while [ $n -ge 0 ]; do
[ -d "${sysfspath}" ] || {
mm_log "error: ignoring modem detection request: no device at ${sysfspath}"
mm_log "error" "ignoring modem detection request: no device at ${sysfspath}"
proto_set_available "${cfg}" 0
return 1
}
@ -177,10 +175,10 @@ mm_wait_for_modem() {
# Check if the modem exists at the given sysfs path
if ! mmcli -m "${sysfspath}" > /dev/null 2>&1
then
mm_log "error: modem not detected at sysfs path"
mm_log "error" "modem not detected at sysfs path"
else
mm_log "modem exported successfully at ${sysfspath}"
mm_log "setting interface '${cfg}' as available"
mm_log "info" "modem exported successfully at ${sysfspath}"
mm_log "info" "setting interface '${cfg}' as available"
proto_set_available "${cfg}" 1
return 0
fi
@ -189,7 +187,7 @@ mm_wait_for_modem() {
n=$((n-step))
done
mm_log "error: timed out waiting for the modem to get exported at ${sysfspath}"
mm_log "error" "timed out waiting for the modem to get exported at ${sysfspath}"
proto_set_available "${cfg}" 0
return 2
}
@ -201,7 +199,7 @@ mm_report_modem_wait() {
parent_sysfspath=$(mm_find_physdev_sysfs_path "$sysfspath")
[ -n "${parent_sysfspath}" ] || {
mm_log "error: parent device sysfspath not found"
mm_log "error" "parent device sysfspath not found"
return
}
@ -212,23 +210,23 @@ mm_report_modem_wait() {
cfg=$(mm_get_modem_config "${parent_sysfspath}")
if [ -n "${cfg}" ]; then
mm_log "interface '${cfg}' is set to configure device '${parent_sysfspath}'"
mm_log "now waiting for modem at sysfs path ${parent_sysfspath}"
mm_log "info" "interface '${cfg}' is set to configure device '${parent_sysfspath}'"
mm_log "info" "now waiting for modem at sysfs path ${parent_sysfspath}"
mm_set_modem_wait_status "${parent_sysfspath}" "processed"
# Launch subshell for the explicit wait
( mm_wait_for_modem "${cfg}" "${parent_sysfspath}" ) > /dev/null 2>&1 &
else
mm_log "no need to wait for modem at sysfs path ${parent_sysfspath}"
mm_log "info" "no need to wait for modem at sysfs path ${parent_sysfspath}"
mm_set_modem_wait_status "${parent_sysfspath}" "ignored"
fi
;;
"processed")
mm_log "already waiting for modem at sysfs path ${parent_sysfspath}"
mm_log "info" "already waiting for modem at sysfs path ${parent_sysfspath}"
;;
"ignored")
;;
*)
mm_log "error: unknown status read for device at sysfs path ${parent_sysfspath}"
mm_log "error" "unknown status read for device at sysfs path ${parent_sysfspath}"
;;
esac
}
@ -236,19 +234,21 @@ mm_report_modem_wait() {
################################################################################
# Cleanup interfaces
mm_cleanup_interface_cb() {
local cfg="$1"
local proto
config_get proto "${cfg}" proto
[ "${proto}" = modemmanager ] || return 0
proto_set_available "${cfg}" 0
}
mm_cleanup_interfaces() {
config_load network
config_foreach mm_cleanup_interface_cb interface
local sysfs_path status
# Do nothing if there is no sysfs cache
[ -f "${MODEMMANAGER_SYSFS_CACHE}" ] || return
while IFS= read -r sysfs_cache_line; do
sysfs_path=$(echo "${sysfs_cache_line}" | awk '{print $1}')
status=$(echo "${sysfs_cache_line}" | awk '{print $2}')
if [ "${status}" = "processed" ]; then
mm_log "debug" "call cleanup for: ${sysfs_path}"
mm_cleanup_interface_by_sysfspath "${sysfs_path}"
fi
done < ${MODEMMANAGER_SYSFS_CACHE}
}
mm_cleanup_interface_by_sysfspath() {
@ -258,7 +258,7 @@ mm_cleanup_interface_by_sysfspath() {
cfg=$(mm_get_modem_config "$dev")
[ -n "${cfg}" ] || return
mm_log "setting interface '$cfg' as unavailable"
mm_log "info" "setting interface '$cfg' as unavailable"
proto_set_available "${cfg}" 0
}
@ -273,7 +273,7 @@ mm_report_event() {
local sysfspath="$4"
# Do not save virtual devices
local virtual
local virtual result
virtual="$(echo "$sysfspath" | cut -d'/' -f4)"
[ "$virtual" = "virtual" ] && {
mm_log "debug" "sysfspath is a virtual device ($sysfspath)"
@ -294,11 +294,15 @@ mm_report_event() {
esac
# Report the event
mm_log "event reported: action=${action}, name=${name}, subsystem=${subsystem}"
mmcli --report-kernel-event="action=${action},name=${name},subsystem=${subsystem}" 1>/dev/null 2>&1 &
mm_log "debug" "Report event: action=${action}, name=${name}, subsystem=${subsystem}"
result=$(mmcli --report-kernel-event="action=${action},name=${name},subsystem=${subsystem}" 2>&1)
if [ "$?" -eq "0" ]; then
# Wait for added modem if a sysfspath is given
[ -n "${sysfspath}" ] && [ "$action" = "add" ] && mm_report_modem_wait "${sysfspath}"
else
mm_log "error" "Couldn't report kernel event: ${result}"
fi
# Wait for added modem if a sysfspath is given
[ -n "${sysfspath}" ] && [ "$action" = "add" ] && mm_report_modem_wait "${sysfspath}"
}
mm_report_event_from_cache_line() {
@ -310,14 +314,11 @@ mm_report_event_from_cache_line() {
subsystem=$(echo "${event_line}" | awk -F ',' '{ print $3 }')
sysfspath=$(echo "${event_line}" | awk -F ',' '{ print $4 }')
mm_log "cached event found: action=${action}, name=${name}, subsystem=${subsystem}, sysfspath=${sysfspath}"
mm_log "debug" "cached event found: action=${action}, name=${name}, subsystem=${subsystem}, sysfspath=${sysfspath}"
mm_report_event "${action}" "${name}" "${subsystem}" "${sysfspath}"
}
mm_report_events_from_cache() {
# Remove the sysfs cache
rm -f "${MODEMMANAGER_SYSFS_CACHE}"
local n=60
local step=1
local mmrunning=0
@ -325,11 +326,11 @@ mm_report_events_from_cache() {
# Wait for ModemManager to be available in the bus
while [ $n -ge 0 ]; do
sleep $step
mm_log "checking if ModemManager is available..."
mm_log "info" "checking if ModemManager is available..."
if ! mmcli -L >/dev/null 2>&1
then
mm_log "ModemManager not yet available"
mm_log "info" "ModemManager not yet available"
else
mmrunning=1
break
@ -338,10 +339,13 @@ mm_report_events_from_cache() {
done
[ ${mmrunning} -eq 1 ] || {
mm_log "error: couldn't report initial kernel events: ModemManager not running"
mm_log "error" "couldn't report initial kernel events: ModemManager not running"
return
}
# Remove the sysfs cache
rm -f "${MODEMMANAGER_SYSFS_CACHE}"
# Report cached kernel events
while IFS= read -r event_line; do
mm_report_event_from_cache_line "${event_line}"

9
modemmanager/files/modemmanager.init Normal file → Executable file
View file

@ -4,12 +4,7 @@
USE_PROCD=1
START=70
stop_service() {
# Load common utils
. /usr/share/ModemManager/modemmanager.common
# Set all configured interfaces as unavailable
mm_cleanup_interfaces
}
LOG_LEVEL="INFO"
start_service() {
# Setup ModemManager service
@ -28,6 +23,8 @@ start_service() {
. /usr/share/ModemManager/modemmanager.common
procd_open_instance
procd_set_param command /usr/sbin/ModemManager-wrapper
procd_append_param command --log-level="$LOG_LEVEL"
[ "$LOG_LEVEL" = "DEBUG" ] && procd_append_param command --debug
procd_set_param respawn "${respawn_threshold:-3600}" "${respawn_timeout:-5}" "${respawn_retry:-5}"
procd_set_param pidfile "${MODEMMANAGER_PID_FILE}"
procd_close_instance

113
modemmanager/files/modemmanager.proto Normal file → Executable file
View file

@ -323,28 +323,20 @@ modemmanager_connected_method_static_ipv6() {
proto_send_update "${interface}"
}
modemmanager_disconnected_method_common() {
local interface="$1"
echo "running disconnection (common)"
proto_notify_error "${interface}" MM_DISCONNECT_IN_PROGRESS
proto_init_update "*" 0
proto_send_update "${interface}"
}
proto_modemmanager_init_config() {
available=1
no_device=1
proto_config_add_string device
proto_config_add_string apn
proto_config_add_string 'allowedauth:list(string)'
proto_config_add_string username
proto_config_add_string password
proto_config_add_string pincode
proto_config_add_string iptype
proto_config_add_string plmn
proto_config_add_int signalrate
proto_config_add_string device
proto_config_add_string apn
proto_config_add_string 'allowedauth:list(string)'
proto_config_add_string username
proto_config_add_string password
proto_config_add_string allowedmode
proto_config_add_string preferredmode
proto_config_add_string pincode
proto_config_add_string iptype
proto_config_add_string plmn
proto_config_add_int signalrate
proto_config_add_boolean lowpower
proto_config_add_boolean allow_roaming
proto_config_add_defaults
@ -359,18 +351,65 @@ append_param() {
connectargs="${connectargs}${param}"
}
modemmanager_set_allowed_mode() {
local device="$1"
local interface="$2"
local allowedmode="$3"
echo "setting allowed mode to '${allowedmode}'"
mmcli --modem="${device}" --set-allowed-modes="${allowedmode}" || {
proto_notify_error "${interface}" MM_INVALID_ALLOWED_MODES_LIST
proto_block_restart "${interface}"
return 1
}
}
modemmanager_set_preferred_mode() {
local device="$1"
local interface="$2"
local allowedmode="$3"
local preferredmode="$4"
[ -z "${preferredmode}" ] && {
echo "no preferred mode configured"
proto_notify_error "${interface}" MM_NO_PREFERRED_MODE_CONFIGURED
proto_block_restart "${interface}"
return 1
}
[ -z "${allowedmode}" ] && {
echo "no allowed mode configured"
proto_notify_error "${interface}" MM_NO_ALLOWED_MODE_CONFIGURED
proto_block_restart "${interface}"
return 1
}
echo "setting preferred mode to '${preferredmode}' (${allowedmode})"
mmcli --modem="${device}" \
--set-preferred-mode="${preferredmode}" \
--set-allowed-modes="${allowedmode}" || {
proto_notify_error "${interface}" MM_FAILED_SETTING_PREFERRED_MODE
proto_block_restart "${interface}"
return 1
}
}
proto_modemmanager_setup() {
local interface="$1"
local modempath modemstatus bearercount bearerpath connectargs bearerstatus beareriface
local bearermethod_ipv4 bearermethod_ipv6 auth cliauth
local operatorname operatorid registration accesstech signalquality
local allowedmode preferredmode
local device apn allowedauth username password pincode iptype plmn metric signalrate allow_roaming
local device apn allowedauth username password pincode
local iptype plmn metric signalrate allow_roaming
local address prefix gateway mtu dns1 dns2
json_get_vars device apn allowedauth username password pincode iptype plmn metric signalrate allow_roaming
json_get_vars device apn allowedauth username password
json_get_vars pincode iptype plmn metric signalrate allow_roaming
json_get_vars allowedmode preferredmode
# validate sysfs path given in config
[ -n "${device}" ] || {
@ -391,6 +430,33 @@ proto_modemmanager_setup() {
}
echo "modem available at ${modempath}"
[ -z "${allowedmode}" ] || {
case "$allowedmode" in
"2g")
modemmanager_set_allowed_mode "$device" \
"$interface" "2g"
;;
"3g")
modemmanager_set_allowed_mode "$device" \
"$interface" "3g"
;;
"4g")
modemmanager_set_allowed_mode "$device" \
"$interface" "4g"
;;
"5g")
modemmanager_set_allowed_mode "$device" \
"$interface" "5g"
;;
*)
modemmanager_set_preferred_mode "$device" \
"$interface" "${allowedmode}" "${preferredmode}"
;;
esac
# check error for allowed_mode and preferred_mode function call
[ "$?" -ne "0" ] && return 1
}
# always cleanup before attempting a new connection, just in case
modemmanager_cleanup_connection "${modemstatus}"
@ -553,7 +619,6 @@ proto_modemmanager_teardown() {
# disconnection handling only requires special treatment in IPv4/PPP
[ "${bearermethod_ipv4}" = "ppp" ] && modemmanager_disconnected_method_ppp_ipv4 "${interface}"
modemmanager_disconnected_method_common "${interface}"
# disconnect
mmcli --modem="${device}" --simple-disconnect ||
@ -561,14 +626,10 @@ proto_modemmanager_teardown() {
# disable
mmcli --modem="${device}" --disable
proto_notify_error "${interface}" MM_MODEM_DISABLED
# low power, only if requested
[ "${lowpower:-0}" -lt 1 ] ||
mmcli --modem="${device}" --set-power-state-low
proto_init_update "*" 0
proto_send_update "$interface"
}
[ -n "$INCLUDE_ONLY" ] || {

4
modemmanager/files/usr/sbin/ModemManager-wrapper Executable file → Normal file
View file

@ -20,7 +20,6 @@ main() {
mkdir -p "${MODEMMANAGER_RUNDIR}"
chmod 0755 "${MODEMMANAGER_RUNDIR}"
mm_cleanup_interfaces
/usr/sbin/ModemManager "$@" 1>/dev/null 2>/dev/null &
CHILD="$!"
@ -28,6 +27,9 @@ main() {
mm_report_events_from_cache
wait "$CHILD"
# Set all configured interfaces as unavailable
mm_cleanup_interfaces
}
main "$@"

View file

@ -0,0 +1,13 @@
--- a/src/plugins/ublox/77-mm-ublox-port-types.rules
+++ b/src/plugins/ublox/77-mm-ublox-port-types.rules
@@ -88,8 +88,8 @@ SUBSYSTEMS=="usb", ATTRS{bInterfaceNumbe
# ttyUSB2 (if #2): secondary
# ttyUSB3 (if #3): unused (ignore)
ATTRS{idVendor}=="05c6", ATTRS{idProduct}=="908b", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_PORT_IGNORE}="1"
-ATTRS{idVendor}=="05c6", ATTRS{idProduct}=="908b", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1", ENV{ID_MM_DEVICE_PROCESS}="1"
-ATTRS{idVendor}=="05c6", ATTRS{idProduct}=="908b", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1", ENV{ID_MM_DEVICE_PROCESS}="1"
+ATTRS{idVendor}=="05c6", ATTRS{idProduct}=="908b", ENV{.MM_USBIFNUM}=="01", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1"
+ATTRS{idVendor}=="05c6", ATTRS{idProduct}=="908b", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1"
ATTRS{idVendor}=="05c6", ATTRS{idProduct}=="908b", ENV{.MM_USBIFNUM}=="03", ENV{ID_MM_PORT_IGNORE}="1"
LABEL="mm_ublox_port_types_end"