<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title><![CDATA[debugging]]></title>
<description><![CDATA[debugging]]></description>
<link>https://christianbryant.codeberg.page/</link>
<atom:link href="https://christianbryant.codeberg.page/rss.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>Tue, 30 Jun 2026 16:44:28 -0700</lastBuildDate>
<item>
  <title><![CDATA[GPS Modem Troubleshooting Report]]></title>
  <description><![CDATA[
<nav id="table-of-contents" role="doc-toc">
<h2>Table of Contents</h2>
<div id="text-table-of-contents" role="doc-toc">
<ul>
<li><a href="#orge8791b0">1. Executive Summary</a></li>
<li><a href="#orgd9f33b7">2. Environment and Affected Components</a></li>
<li><a href="#orgb77f82d">3. Symptoms</a></li>
<li><a href="#orgadc4c59">4. Root Cause Analysis</a>
<ul>
<li><a href="#org130c54b">4.1. Technical root cause</a></li>
<li><a href="#orge1251e2">4.2. Contributing factor: bad/legacy modprobe configuration</a></li>
<li><a href="#orgb54908b">4.3. Contributing factor: driver support asymmetry</a></li>
<li><a href="#org940bece">4.4. 5 Whys</a></li>
</ul>
</li>
<li><a href="#org040b209">5. Resolution and Recovery</a>
<ul>
<li><a href="#org7c85900">5.1. Step 1: Confirm the bad binding</a></li>
<li><a href="#org6ba8d32">5.2. Step 2: Temporarily block the serial driver</a></li>
<li><a href="#orgee8f852">5.3. Step 3: Confirm modem model and USB composition</a></li>
<li><a href="#orgc837299">5.4. Step 4: Restore serial ports without stealing QMI</a></li>
<li><a href="#org3e8594f">5.5. Step 5: Make the fix persistent</a></li>
<li><a href="#org7e95058">5.6. Step 6: Validate after reboot</a></li>
</ul>
</li>
<li><a href="#org8a62544">6. Current Known-Good Configuration</a>
<ul>
<li><a href="#org06e4521">6.1. Driver binding</a></li>
<li><a href="#orgfd2e2d0">6.2. Device nodes</a></li>
<li><a href="#orgc50a4cf">6.3. Modem composition</a></li>
<li><a href="#org707a0bd">6.4. Correct QMI command style</a></li>
</ul>
</li>
<li><a href="#org808f302">7. Action Items</a>
<ul>
<li><a href="#org86d7f88">7.1. Completed</a></li>
<li><a href="#org335b20b">7.2. Recommended follow-up</a></li>
</ul>
</li>
<li><a href="#org04f5da5">8. Quick Reference</a>
<ul>
<li><a href="#org88ff280">8.1. Good state</a></li>
<li><a href="#orgb10f682">8.2. Bad state</a></li>
<li><a href="#orge3d91fe">8.3. Fast diagnostic commands</a></li>
<li><a href="#org1deb5c9">8.4. Emergency manual recovery</a></li>
<li><a href="#orgeef9b91">8.5. Persistent configuration files</a></li>
</ul>
</li>
<li><a href="#org1003ea4">9. Notes and Caveats</a></li>
</ul>
</div>
</nav>
<div id="outline-container-orge8791b0" class="outline-2">
<h2 id="orge8791b0"><span class="section-number-2">1.</span> Executive Summary</h2>
<div class="outline-text-2" id="text-1">
<p>
On a Panasonic Toughbook CF-31-5 running Xubuntu 26.04 LTS, the Sierra Wireless modem stopped exposing the QMI control device <code>/dev/cdc-wdm0</code>. The system still showed <code>/dev/ttyUSB*</code> serial devices initially, but GPS/QMI tooling failed because commands targeting <code>/dev/cdc-wdm0</code> could no longer run.
</p>

<p>
The modem appeared on USB as:
</p>

<pre class="example" id="orgef47f47">
Bus 001 Device 005: ID 1199:9041 Sierra Wireless, Inc. EM7305/EM7355-family Modem
</pre>

<p>
During recovery, <code>qmicli</code> reported the actual modem model as:
</p>

<pre class="example" id="org29f704a">
Model: 'EM7355'
</pre>

<p>
The final confirmed working state after reboot was:
</p>

<pre class="example" id="org35f89be">
If 0 -&gt; option      -&gt; /dev/ttyUSB0
If 2 -&gt; option      -&gt; /dev/ttyUSB1
If 3 -&gt; option      -&gt; /dev/ttyUSB2
If 8 -&gt; qmi_wwan    -&gt; /dev/cdc-wdm0
</pre>

<p>
The active USB composition was confirmed as composition 6:
</p>

<pre class="example" id="orgc5cfc22">
[*] USB composition 6: DM, NMEA, AT, QMI
</pre>

<p>
This is the desired composition for this setup because it provides serial interfaces for diagnostic/AT/NMEA functions and a QMI control interface for <code>qmicli</code>.
</p>

<p>
The issue was not a failed modem or missing QMI support in the kernel. The immediate failure was that the Linux <code>option</code> serial driver grabbed interface 8, which should have been owned by <code>qmi_wwan</code>. Because <code>qmi_wwan</code> could not bind to interface 8, the kernel did not create <code>/dev/cdc-wdm0</code>.
</p>

<p>
The recovery was completed by ensuring <code>qmi_wwan</code> claimed interface 8 first, then adding the modem USB ID dynamically to the <code>option1</code> usb-serial driver so the serial interfaces could bind without taking the QMI interface.
</p>
</div>
</div>
<div id="outline-container-orgd9f33b7" class="outline-2">
<h2 id="orgd9f33b7"><span class="section-number-2">2.</span> Environment and Affected Components</h2>
<div class="outline-text-2" id="text-2">
<table>


<colgroup>
<col  class="org-left">

<col  class="org-left">
</colgroup>
<thead>
<tr>
<th scope="col" class="org-left">Item</th>
<th scope="col" class="org-left">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-left">Hardware</td>
<td class="org-left">Panasonic Toughbook CF-31-5</td>
</tr>

<tr>
<td class="org-left">Operating system</td>
<td class="org-left">Xubuntu 26.04 LTS</td>
</tr>

<tr>
<td class="org-left">Modem USB ID</td>
<td class="org-left"><code>1199:9041</code></td>
</tr>

<tr>
<td class="org-left">Reported model via <code>qmicli</code></td>
<td class="org-left"><code>EM7355</code></td>
</tr>

<tr>
<td class="org-left">Initial symptom</td>
<td class="org-left"><code>/dev/cdc-wdm0</code> disappeared</td>
</tr>

<tr>
<td class="org-left">Serial devices</td>
<td class="org-left"><code>/dev/ttyUSB*</code> existed initially, later restored after fix</td>
</tr>

<tr>
<td class="org-left">Desired QMI driver</td>
<td class="org-left"><code>qmi_wwan</code></td>
</tr>

<tr>
<td class="org-left">Desired WDM/control driver</td>
<td class="org-left"><code>cdc_wdm</code></td>
</tr>

<tr>
<td class="org-left">Desired serial driver</td>
<td class="org-left"><code>option</code> / <code>option1</code> usb-serial layer</td>
</tr>

<tr>
<td class="org-left">QMI interface</td>
<td class="org-left">USB interface <code>1-6:1.8</code></td>
</tr>
</tbody>
</table>
</div>
</div>
<div id="outline-container-orgb77f82d" class="outline-2">
<h2 id="orgb77f82d"><span class="section-number-2">3.</span> Symptoms</h2>
<div class="outline-text-2" id="text-3">
<p>
The primary symptom was that <code>/dev/cdc-wdm0</code> disappeared. As a result, QMI/GPS management commands failed, including commands like:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo qmicli --device-open-mbim -p -d /dev/cdc-wdm0 --dms-swi-get-usb-composition
</pre>
</div>

<p>
Later analysis showed that because the modem was active in QMI composition 6, the correct command style should be plain QMI, without <code>--device-open-mbim</code>:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo qmicli -p -d /dev/cdc-wdm0 --dms-get-model
sudo qmicli -p -d /dev/cdc-wdm0 --dms-swi-get-usb-composition
</pre>
</div>

<p>
Initial <code>dmesg</code> output confirmed that the modem was detected and the QMI-related drivers existed:
</p>

<pre class="example" id="orgb341882">
usb 1-6: New USB device found, idVendor=1199, idProduct=9041
usb 1-6: Manufacturer: Sierra Wireless, Incorporated
usbcore: registered new interface driver cdc_wdm
usbcore: registered new interface driver qmi_wwan
</pre>

<p>
However, there was initially no successful bind message like:
</p>

<pre class="example" id="org9cde8a1">
qmi_wwan 1-6:1.8: cdc-wdm0: USB WDM device
</pre>

<p>
The initial bad <code>lsusb -t</code> state showed interface 8 bound to <code>option</code> instead of <code>qmi_wwan</code>:
</p>

<pre class="example" id="org3c318dd">
|__ Port 006: Dev 005, If 0, Class=Vendor Specific Class, Driver=option, 480M
|__ Port 006: Dev 005, If 2, Class=Vendor Specific Class, Driver=option, 480M
|__ Port 006: Dev 005, If 3, Class=Vendor Specific Class, Driver=option, 480M
|__ Port 006: Dev 005, If 8, Class=Vendor Specific Class, Driver=option, 480M
</pre>

<p>
This was the key failure condition.
</p>
</div>
</div>
<div id="outline-container-orgadc4c59" class="outline-2">
<h2 id="orgadc4c59"><span class="section-number-2">4.</span> Root Cause Analysis</h2>
<div class="outline-text-2" id="text-4">
</div>
<div id="outline-container-org130c54b" class="outline-3">
<h3 id="org130c54b"><span class="section-number-3">4.1.</span> Technical root cause</h3>
<div class="outline-text-3" id="text-4-1">
<p>
The modem was in a valid QMI-capable USB composition, but the Linux serial driver <code>option</code> claimed USB interface <code>1-6:1.8</code>. That interface needed to be claimed by <code>qmi_wwan</code> so that <code>cdc_wdm</code> could create <code>/dev/cdc-wdm0</code>.
</p>

<p>
When <code>option</code> owned interface 8, the system still had serial-style modem behavior, but it lacked the QMI control device.
</p>

<p>
The correct binding is:
</p>

<pre class="example" id="orgc4fbf26">
If 0 -&gt; option
If 2 -&gt; option
If 3 -&gt; option
If 8 -&gt; qmi_wwan
</pre>

<p>
The incorrect binding was:
</p>

<pre class="example" id="org6ec641d">
If 0 -&gt; option
If 2 -&gt; option
If 3 -&gt; option
If 8 -&gt; option
</pre>
</div>
</div>
<div id="outline-container-orge1251e2" class="outline-3">
<h3 id="orge1251e2"><span class="section-number-3">4.2.</span> Contributing factor: bad/legacy modprobe configuration</h3>
<div class="outline-text-3" id="text-4-2">
<p>
A legacy configuration file existed:
</p>

<pre class="example" id="org9624755">
/etc/modprobe.d/sierra-em7305.conf:options option vendor=0x1199 product=0x9041
</pre>

<p>
This produced kernel messages such as:
</p>

<pre class="example" id="org1573d96">
option: unknown parameter 'vendor' ignored
option: unknown parameter 'product' ignored
</pre>

<p>
Those parameters are not valid for the <code>option</code> driver on this system. The file was at minimum noisy and misleading, and it was part of the configuration path that caused confusion around <code>option</code> binding.
</p>

<p>
The file was disabled by renaming it:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo mv /etc/modprobe.d/sierra-em7305.conf /etc/modprobe.d/sierra-em7305.conf.disabled
</pre>
</div>
</div>
</div>
<div id="outline-container-orgb54908b" class="outline-3">
<h3 id="orgb54908b"><span class="section-number-3">4.3.</span> Contributing factor: driver support asymmetry</h3>
<div class="outline-text-3" id="text-4-3">
<p>
The <code>qmi_wwan</code> module did know about this modem/interface:
</p>

<pre class="example" id="org46ab278">
alias: usb:v1199p9041d*dc*dsc*dp*ic*isc*ip*in0A*
alias: usb:v1199p9041d*dc*dsc*dp*ic*isc*ip*in08*
</pre>

<p>
However, after disabling the bad <code>options option vendor/product</code> configuration, the serial interfaces did not bind automatically. Adding the USB ID dynamically to the <code>option1</code> usb-serial driver restored the serial ports:
</p>

<div class="org-src-container">
<pre class="src src-sh">echo 1199 9041 | sudo tee /sys/bus/usb-serial/drivers/option1/new_id
</pre>
</div>

<p>
This allowed <code>option</code> to claim interfaces 0, 2, and 3 while leaving interface 8 with <code>qmi_wwan</code>.
</p>
</div>
</div>
<div id="outline-container-org940bece" class="outline-3">
<h3 id="org940bece"><span class="section-number-3">4.4.</span> 5 Whys</h3>
<div class="outline-text-3" id="text-4-4">
<ol class="org-ol">
<li><p>
Why did GPS/QMI commands fail?
</p>

<p>
Because <code>/dev/cdc-wdm0</code> was missing, so <code>qmicli</code> could not open the modem control device.
</p></li>

<li><p>
Why was <code>/dev/cdc-wdm0</code> missing?
</p>

<p>
Because <code>qmi_wwan</code> did not bind to the modem's QMI interface, so <code>cdc_wdm</code> did not create the WDM character device.
</p></li>

<li><p>
Why did <code>qmi_wwan</code> not bind?
</p>

<p>
Because USB interface <code>1-6:1.8</code>, which should have been handled by <code>qmi_wwan</code>, was already claimed by the <code>option</code> serial driver.
</p></li>

<li><p>
Why did <code>option</code> claim the QMI interface?
</p>

<p>
The system had legacy/custom Sierra modem configuration involving the <code>option</code> driver, including an invalid <code>/etc/modprobe.d/sierra-em7305.conf</code> file. The serial driver was loading/binding too broadly or too early relative to <code>qmi_wwan</code>.
</p></li>

<li><p>
Why was this not caught earlier?
</p>

<p>
The modem still partially worked as a serial USB device, so the failure appeared as a GPS/QMI problem rather than a USB driver binding problem. The absence of <code>/dev/cdc-wdm0</code> was the visible symptom, but the underlying issue was only clear after inspecting <code>lsusb -t</code> and seeing interface 8 bound to the wrong driver.
</p></li>
</ol>
</div>
</div>
</div>
<div id="outline-container-org040b209" class="outline-2">
<h2 id="org040b209"><span class="section-number-2">5.</span> Resolution and Recovery</h2>
<div class="outline-text-2" id="text-5">
</div>
<div id="outline-container-org7c85900" class="outline-3">
<h3 id="org7c85900"><span class="section-number-3">5.1.</span> Step 1: Confirm the bad binding</h3>
<div class="outline-text-3" id="text-5-1">
<p>
The bad state was identified with:
</p>

<div class="org-src-container">
<pre class="src src-sh">lsusb -t
</pre>
</div>

<p>
Bad state:
</p>

<pre class="example" id="orgbf68d00">
If 8, Driver=option
</pre>

<p>
Good state:
</p>

<pre class="example" id="orgf1bf700">
If 8, Driver=qmi_wwan
</pre>
</div>
</div>
<div id="outline-container-org6ba8d32" class="outline-3">
<h3 id="org6ba8d32"><span class="section-number-3">5.2.</span> Step 2: Temporarily block the serial driver</h3>
<div class="outline-text-3" id="text-5-2">
<p>
The <code>option</code> driver was temporarily blocked to allow <code>qmi_wwan</code> to claim interface 8 first:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo tee /etc/modprobe.d/disable-option-temporarily.conf &gt;/dev/null &lt;&lt;'EOF'
blacklist option
install option /bin/false
EOF
</pre>
</div>

<p>
The modem was then rebound and the QMI modules were loaded:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo sh -c 'echo 1-6 &gt; /sys/bus/usb/drivers/usb/unbind'
sudo rmmod option 2&gt;/dev/null || true
sudo rmmod usb_wwan 2&gt;/dev/null || true
sudo modprobe cdc_wdm
sudo modprobe qmi_wwan
sudo sh -c 'echo 1-6 &gt; /sys/bus/usb/drivers/usb/bind'
</pre>
</div>

<p>
This restored <code>/dev/cdc-wdm0</code>.
</p>

<p>
Successful <code>dmesg</code> evidence:
</p>

<pre class="example" id="orga04892d">
qmi_wwan 1-6:1.8: cdc-wdm0: USB WDM device
qmi_wwan 1-6:1.8 wwan0: register 'qmi_wwan' at usb-0000:00:14.0-6, WWAN/QMI device
qmi_wwan 1-6:1.8 wwp0s20u6i8: renamed from wwan0
</pre>
</div>
</div>
<div id="outline-container-orgee8f852" class="outline-3">
<h3 id="orgee8f852"><span class="section-number-3">5.3.</span> Step 3: Confirm modem model and USB composition</h3>
<div class="outline-text-3" id="text-5-3">
<p>
After <code>/dev/cdc-wdm0</code> returned, <code>qmicli</code> confirmed the modem model:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo qmicli -p -d /dev/cdc-wdm0 --dms-get-model
</pre>
</div>

<p>
Output:
</p>

<pre class="example" id="org8a5b071">
[/dev/cdc-wdm0] Device model retrieved:
        Model: 'EM7355'
</pre>

<p>
The USB composition was confirmed:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo qmicli -p -d /dev/cdc-wdm0 --dms-swi-get-usb-composition
</pre>
</div>

<p>
Output:
</p>

<pre class="example" id="org877f9fa">
[/dev/cdc-wdm0] Successfully retrieved USB compositions:
            USB composition 1: HIP, DM, NMEA, AT, MDM1, MS
        [*] USB composition 6: DM, NMEA, AT, QMI
            USB composition 7: DM, NMEA, AT, RMNET1, RMNET2, RMNET3
            USB composition 8: DM, NMEA, AT, MBIM
            USB composition 9: MBIM
            USB composition 10: NMEA, MBIM
            USB composition 11: DM, MBIM
            USB composition 12: DM, NMEA, MBIM
            USB composition 14: Dual configuration: USB composition 6 and USB composition 9
            USB composition 19: Dual configuration: USB composition 7 and USB composition 9
</pre>

<p>
No USB composition change was needed. Composition 6 was correct for QMI + AT/NMEA usage.
</p>
</div>
</div>
<div id="outline-container-orgc837299" class="outline-3">
<h3 id="orgc837299"><span class="section-number-3">5.4.</span> Step 4: Restore serial ports without stealing QMI</h3>
<div class="outline-text-3" id="text-5-4">
<p>
After <code>qmi_wwan</code> owned interface 8, the serial ID was added dynamically to the <code>option1</code> usb-serial driver:
</p>

<div class="org-src-container">
<pre class="src src-sh">echo 1199 9041 | sudo tee /sys/bus/usb-serial/drivers/option1/new_id
</pre>
</div>

<p>
This restored the serial ports while keeping QMI intact.
</p>

<p>
Working state before reboot:
</p>

<pre class="example" id="org35350ed">
|__ Port 006: Dev 005, If 0, Class=Vendor Specific Class, Driver=option, 480M
|__ Port 006: Dev 005, If 2, Class=Vendor Specific Class, Driver=option, 480M
|__ Port 006: Dev 005, If 3, Class=Vendor Specific Class, Driver=option, 480M
|__ Port 006: Dev 005, If 8, Class=Vendor Specific Class, Driver=qmi_wwan, 480M
</pre>

<p>
Devices restored:
</p>

<pre class="example" id="org2af59cc">
/dev/ttyUSB0
/dev/ttyUSB1
/dev/ttyUSB2
/dev/cdc-wdm0
</pre>
</div>
</div>
<div id="outline-container-org3e8594f" class="outline-3">
<h3 id="org3e8594f"><span class="section-number-3">5.5.</span> Step 5: Make the fix persistent</h3>
<div class="outline-text-3" id="text-5-5">
<p>
The bad legacy file was disabled:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo mv /etc/modprobe.d/sierra-em7305.conf /etc/modprobe.d/sierra-em7305.conf.disabled 2&gt;/dev/null || true
</pre>
</div>

<p>
A QMI-first soft dependency was created:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo tee /etc/modprobe.d/em7355-qmi-first.conf &gt;/dev/null &lt;&lt;'EOF'
softdep option pre: qmi_wwan cdc_wdm
EOF
</pre>
</div>

<p>
A udev rule was created to add the modem USB ID to the <code>option1</code> usb-serial driver:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo tee /etc/udev/rules.d/99-em7355-option-serial.rules &gt;/dev/null &lt;&lt;'EOF'
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="1199", ATTR{idProduct}=="9041", RUN+="/bin/sh -c 'modprobe option; echo 1199 9041 &gt; /sys/bus/usb-serial/drivers/option1/new_id 2&gt;/dev/null || true'"
EOF
</pre>
</div>

<p>
Rules/initramfs were refreshed:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo udevadm control --reload-rules
sudo update-initramfs -u 2&gt;/dev/null || true
</pre>
</div>
</div>
</div>
<div id="outline-container-org7e95058" class="outline-3">
<h3 id="org7e95058"><span class="section-number-3">5.6.</span> Step 6: Validate after reboot</h3>
<div class="outline-text-3" id="text-5-6">
<p>
After reboot, the system showed the desired layout:
</p>

<pre class="example" id="org9fa25e7">
|__ Port 006: Dev 004, If 0, Class=Vendor Specific Class, Driver=option, 480M
|__ Port 006: Dev 004, If 2, Class=Vendor Specific Class, Driver=option, 480M
|__ Port 006: Dev 004, If 3, Class=Vendor Specific Class, Driver=option, 480M
|__ Port 006: Dev 004, If 8, Class=Vendor Specific Class, Driver=qmi_wwan, 480M
</pre>

<p>
Device nodes existed:
</p>

<pre class="example" id="org7d0b761">
crw------- 1 root root    180, 0 Jun 28 00:16 /dev/cdc-wdm0
crw-rw---- 1 root dialout 188, 0 Jun 28 00:16 /dev/ttyUSB0
crw-rw---- 1 root dialout 188, 1 Jun 28 00:16 /dev/ttyUSB1
crw-rw---- 1 root dialout 188, 2 Jun 28 00:16 /dev/ttyUSB2
</pre>

<p>
<code>qmicli</code> validation succeeded:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo qmicli -p -d /dev/cdc-wdm0 --dms-get-model
</pre>
</div>

<p>
Output:
</p>

<pre class="example" id="org4395206">
[/dev/cdc-wdm0] Device model retrieved:
        Model: 'EM7355'
</pre>
</div>
</div>
</div>
<div id="outline-container-org8a62544" class="outline-2">
<h2 id="org8a62544"><span class="section-number-2">6.</span> Current Known-Good Configuration</h2>
<div class="outline-text-2" id="text-6">
</div>
<div id="outline-container-org06e4521" class="outline-3">
<h3 id="org06e4521"><span class="section-number-3">6.1.</span> Driver binding</h3>
<div class="outline-text-3" id="text-6-1">
<pre class="example" id="org15a6087">
If 0 -&gt; option
If 2 -&gt; option
If 3 -&gt; option
If 8 -&gt; qmi_wwan
</pre>
</div>
</div>
<div id="outline-container-orgfd2e2d0" class="outline-3">
<h3 id="orgfd2e2d0"><span class="section-number-3">6.2.</span> Device nodes</h3>
<div class="outline-text-3" id="text-6-2">
<pre class="example" id="org10df1d5">
/dev/cdc-wdm0
/dev/ttyUSB0
/dev/ttyUSB1
/dev/ttyUSB2
</pre>
</div>
</div>
<div id="outline-container-orgc50a4cf" class="outline-3">
<h3 id="orgc50a4cf"><span class="section-number-3">6.3.</span> Modem composition</h3>
<div class="outline-text-3" id="text-6-3">
<pre class="example" id="org8e7ef26">
USB composition 6: DM, NMEA, AT, QMI
</pre>
</div>
</div>
<div id="outline-container-org707a0bd" class="outline-3">
<h3 id="org707a0bd"><span class="section-number-3">6.4.</span> Correct QMI command style</h3>
<div class="outline-text-3" id="text-6-4">
<p>
Because the active composition is QMI, use plain QMI commands:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo qmicli -p -d /dev/cdc-wdm0 --dms-get-model
sudo qmicli -p -d /dev/cdc-wdm0 --dms-swi-get-usb-composition
</pre>
</div>

<p>
Do not use <code>--device-open-mbim</code> unless the modem is intentionally switched to an MBIM composition such as composition 8, 9, 10, 11, 12, 14, or 19.
</p>
</div>
</div>
</div>
<div id="outline-container-org808f302" class="outline-2">
<h2 id="org808f302"><span class="section-number-2">7.</span> Action Items</h2>
<div class="outline-text-2" id="text-7">
</div>
<div id="outline-container-org86d7f88" class="outline-3">
<h3 id="org86d7f88"><span class="section-number-3">7.1.</span> Completed</h3>
<div class="outline-text-3" id="text-7-1">
<ul class="org-ul">
<li class="on"><code>[X]</code> Confirmed modem was detected on USB as <code>1199:9041</code>.</li>
<li class="on"><code>[X]</code> Confirmed <code>qmi_wwan</code> supports <code>1199:9041</code> interface 8 and 10.</li>
<li class="on"><code>[X]</code> Identified incorrect driver binding: interface 8 bound to <code>option</code>.</li>
<li class="on"><code>[X]</code> Temporarily blocked <code>option</code> to allow <code>qmi_wwan</code> to claim interface 8.</li>
<li class="on"><code>[X]</code> Restored <code>/dev/cdc-wdm0</code>.</li>
<li class="on"><code>[X]</code> Confirmed modem model as <code>EM7355</code>.</li>
<li class="on"><code>[X]</code> Confirmed active USB composition 6: <code>DM, NMEA, AT, QMI</code>.</li>
<li class="on"><code>[X]</code> Disabled invalid legacy modprobe configuration.</li>
<li class="on"><code>[X]</code> Restored serial ports using <code>option1/new_id</code>.</li>
<li class="on"><code>[X]</code> Added persistent QMI-first rule and udev serial binding rule.</li>
<li class="on"><code>[X]</code> Rebooted and confirmed working state.</li>
</ul>
</div>
</div>
<div id="outline-container-org335b20b" class="outline-3">
<h3 id="org335b20b"><span class="section-number-3">7.2.</span> Recommended follow-up</h3>
<div class="outline-text-3" id="text-7-2">
<ul class="org-ul">
<li class="off"><code>[&#xa0;]</code> <p>
Save a backup copy of these files:
</p>

<div class="org-src-container">
<pre class="src src-sh">sudo cp /etc/modprobe.d/em7355-qmi-first.conf ~/em7355-qmi-first.conf.backup
sudo cp /etc/udev/rules.d/99-em7355-option-serial.rules ~/99-em7355-option-serial.rules.backup
</pre>
</div></li>

<li class="off"><code>[&#xa0;]</code> <p>
After future kernel or OS updates, verify the driver layout:
</p>

<div class="org-src-container">
<pre class="src src-sh">lsusb -t
ls -l /dev/cdc-wdm*
ls -l /dev/ttyUSB*
sudo qmicli -p -d /dev/cdc-wdm0 --dms-get-model
</pre>
</div></li>

<li class="off"><code>[&#xa0;]</code> If GPS scripts depend on fixed <code>ttyUSB</code> numbers, consider adding udev symlinks for stable names such as <code>/dev/gps-nmea</code> and <code>/dev/modem-at</code>.</li>

<li class="off"><code>[&#xa0;]</code> Update any scripts that use <code>--device-open-mbim</code> unless the modem is deliberately switched to MBIM. Current composition 6 should use plain QMI.</li>

<li class="off"><code>[&#xa0;]</code> Keep <code>sierra-em7305.conf.disabled</code> for reference temporarily, then delete it after several successful reboots/updates.</li>
</ul>
</div>
</div>
</div>
<div id="outline-container-org04f5da5" class="outline-2">
<h2 id="org04f5da5"><span class="section-number-2">8.</span> Quick Reference</h2>
<div class="outline-text-2" id="text-8">
</div>
<div id="outline-container-org88ff280" class="outline-3">
<h3 id="org88ff280"><span class="section-number-3">8.1.</span> Good state</h3>
<div class="outline-text-3" id="text-8-1">
<pre class="example" id="orgfa5e7b3">
If 8, Driver=qmi_wwan
/dev/cdc-wdm0 exists
/dev/ttyUSB0-2 exist
</pre>
</div>
</div>
<div id="outline-container-orgb10f682" class="outline-3">
<h3 id="orgb10f682"><span class="section-number-3">8.2.</span> Bad state</h3>
<div class="outline-text-3" id="text-8-2">
<pre class="example" id="org8b2179a">
If 8, Driver=option
/dev/cdc-wdm0 missing
</pre>
</div>
</div>
<div id="outline-container-orge3d91fe" class="outline-3">
<h3 id="orge3d91fe"><span class="section-number-3">8.3.</span> Fast diagnostic commands</h3>
<div class="outline-text-3" id="text-8-3">
<div class="org-src-container">
<pre class="src src-sh">lsusb -t
ls -l /dev/cdc-wdm* 2&gt;/dev/null
ls -l /dev/ttyUSB* 2&gt;/dev/null
sudo qmicli -p -d /dev/cdc-wdm0 --dms-get-model
sudo qmicli -p -d /dev/cdc-wdm0 --dms-swi-get-usb-composition
</pre>
</div>
</div>
</div>
<div id="outline-container-org1deb5c9" class="outline-3">
<h3 id="org1deb5c9"><span class="section-number-3">8.4.</span> Emergency manual recovery</h3>
<div class="outline-text-3" id="text-8-4">
<p>
Use this only if <code>/dev/cdc-wdm0</code> disappears again because interface 8 is stolen by <code>option</code>.
</p>

<div class="org-src-container">
<pre class="src src-sh"># Temporarily stop option from holding the QMI interface.
sudo sh -c 'echo 1-6:1.8 &gt; /sys/bus/usb/drivers/option/unbind' 2&gt;/dev/null || true

# Ensure QMI support is loaded.
sudo modprobe cdc_wdm
sudo modprobe qmi_wwan

# Bind interface 8 to qmi_wwan.
sudo sh -c 'echo 1-6:1.8 &gt; /sys/bus/usb/drivers/qmi_wwan/bind'

# Restore serial interfaces if needed.
sudo modprobe option
echo 1199 9041 | sudo tee /sys/bus/usb-serial/drivers/option1/new_id
</pre>
</div>
</div>
</div>
<div id="outline-container-orgeef9b91" class="outline-3">
<h3 id="orgeef9b91"><span class="section-number-3">8.5.</span> Persistent configuration files</h3>
<div class="outline-text-3" id="text-8-5">
<p>
<code>/etc/modprobe.d/em7355-qmi-first.conf</code>:
</p>

<div class="org-src-container">
<pre class="src src-conf">softdep option pre: qmi_wwan cdc_wdm
</pre>
</div>

<p>
<code>/etc/udev/rules.d/99-em7355-option-serial.rules</code>:
</p>

<div class="org-src-container">
<pre class="src src-conf">ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="1199", ATTR{idProduct}=="9041", RUN+="/bin/sh -c 'modprobe option; echo 1199 9041 &gt; /sys/bus/usb-serial/drivers/option1/new_id 2&gt;/dev/null || true'"
</pre>
</div>
</div>
</div>
</div>
<div id="outline-container-org1003ea4" class="outline-2">
<h2 id="org1003ea4"><span class="section-number-2">9.</span> Notes and Caveats</h2>
<div class="outline-text-2" id="text-9">
<ul class="org-ul">
<li>The modem was initially described as an EM7305, but <code>qmicli</code> identified it as <code>EM7355</code>. This report uses <code>EM7355</code> for the working configuration while preserving the original context.</li>
<li>The modem did not require a USB composition change. Composition 6 was already active and correct.</li>
<li>The exact historical reason for the old <code>sierra-em7305.conf</code> file is unknown. It may have been from a prior workaround or installation attempt.</li>
<li>If the USB device path changes from <code>1-6</code> in the future, commands that hard-code <code>1-6</code> may need adjustment. <code>lsusb -t</code> and <code>dmesg</code> can be used to identify the current path.</li>
<li>Interface 8 must remain bound to <code>qmi_wwan</code> for <code>/dev/cdc-wdm0</code> to exist.</li>
</ul>
</div>
</div>
<div class="taglist"><a href="https://christianbryant.codeberg.page/tags/index.html"><span class="tag-label">Tags</span></a><span class="tag-separator">: </span><span class="taglist__tags"><a href="https://christianbryant.codeberg.page/tags/tag-xubuntu.html" class="tag" data-tag="xubuntu" data-index="0">xubuntu</a> <a href="https://christianbryant.codeberg.page/tags/tag-linux.html" class="tag" data-tag="linux" data-index="1">linux</a> <a href="https://christianbryant.codeberg.page/tags/tag-gps.html" class="tag" data-tag="gps" data-index="2">gps</a> <a href="https://christianbryant.codeberg.page/tags/tag-gpsd.html" class="tag" data-tag="gpsd" data-index="3">gpsd</a> <a href="https://christianbryant.codeberg.page/tags/tag-qmi.html" class="tag" data-tag="qmi" data-index="4">qmi</a> <a href="https://christianbryant.codeberg.page/tags/tag-toughbook.html" class="tag" data-tag="toughbook" data-index="5">toughbook</a> <a href="https://christianbryant.codeberg.page/tags/tag-sierra.html" class="tag" data-tag="sierra" data-index="6">sierra</a> <a href="https://christianbryant.codeberg.page/tags/tag-wireless.html" class="tag" data-tag="wireless" data-index="7">wireless</a> <a href="https://christianbryant.codeberg.page/tags/tag-modem.html" class="tag" data-tag="modem" data-index="8">modem</a> </span></div>]]></description>
  <category><![CDATA[xubuntu]]></category>
  <category><![CDATA[linux]]></category>
  <category><![CDATA[gps]]></category>
  <category><![CDATA[gpsd]]></category>
  <category><![CDATA[qmi]]></category>
  <category><![CDATA[toughbook]]></category>
  <category><![CDATA[sierra]]></category>
  <category><![CDATA[wireless]]></category>
  <category><![CDATA[modem]]></category>
  <link>https://christianbryant.codeberg.page/posts/2026-06-28-gps-modem.html</link>
  <guid>https://christianbryant.codeberg.page/posts/2026-06-28-gps-modem.html</guid>
  <pubDate>Sun, 28 Jun 2026 00:00:00 -0700</pubDate>
</item>
</channel>
</rss>
