Problem: The huawei_cdc_ncm driver (for the 4G LTE dongle Huawei
E3276) gets unregistered and the control device /dev/cdc-wdmN
disappears after sending exactly 121 AT commands to the device. After
a few seconds, the driver is re-registered and the control device
reappears. Test program causing the error included at the end of this
message.

Keywords: huawei_cdc_ncm, LTE, AT commands, cdc-wdm

Detailed problem description:

The behavior has been verified on kernel 3.16.0 and on kernel 3.17.1,
on a 64-bit Core i5 x86 machine and on a a smaller embedded 32-bit x86
machine. Exact command does not matter, used 'ATI' and  'AT^HCSQ?'
with same result. Distros used are Kubuntu 14.04.1 LTS on the i5 and
Debian Wheezy on the embedded machine.

Kernel modules: huawei_cdc_ncm, cdc_ncm

The test program contains some rudimentary C++ but should be readable
even to die-hard C guys ;) The program is crude but hopefully useful
for debugging.
If more info is needed, let me know and I will provide it.

Best regards,

/Erik Alapää


//
// Program that causes temporary loss of cdc-wdmN device and huawei_cdc_ncm
// driver reload after 121 AT commands sent.
//
// No makefile, just compile with 'g++ -g wdm_err.cpp -o wdm_err'.
//
// Usage, see 'Usage: ' message in the code below.
//
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdexcept>
#include <string>
#include <iostream>
#include <fstream>

using std::string;
using std::cout;
using std::runtime_error;
using std::endl;
using std::fstream;

int main(int argc, char* argv[])
{
    fd_set rfds;
    fd_set wfds;

    struct timeval tv;
    struct timeval tv2;
    int retval;
    int n;

    const int SZ = 512;
    char errbuf[SZ];
    char ctrlin_buf[SZ];

    //string command("AT^HCSQ?\n");
    string command("ATI\n");
    string response;
    string resp_line;
    fstream at_file;

    int sleep_us = 0;
    int sendcount = 0;

    char CTRL_DEVICE[SZ];

    // Get file descriptor for select()
    if (argc == 3)
    {
        cout << "Setting AT ctrl device to \'" << argv[1] << "\'\n";
        strcpy(CTRL_DEVICE, argv[1]);
        cout << "Sleep interval " << sleep_us << " us\n";
    }
    else
    {
        cout << "Usage: rw2 <at-ctrl-device> <sleeptime in us> (ctrl
is typically /dev/cdc-wdmN)\n\n";
        throw std::runtime_error("Too few args, no ctrl device specified!");
    }
    int ctrl = open(CTRL_DEVICE, O_RDWR);
    if (ctrl == -1)
    {
        throw std::runtime_error(strerror_r(errno, errbuf, SZ));
    }

    sleep_us = atoi(argv[2]);

    // Get fstream for C++-style reading and writing
    at_file.open(CTRL_DEVICE, std::fstream::in | std::fstream::out |
std::fstream::app);
    if (!at_file)
    {
        throw runtime_error("Could not open wdm device file!\n");
    }

    for (;;)
    {
        tv.tv_sec = 10;
        tv.tv_usec = 0;
        FD_ZERO(&rfds);
        FD_SET(ctrl, &rfds);

        FD_ZERO(&wfds);
        FD_SET(ctrl, &wfds);

        if (at_file.bad())
        {
            throw runtime_error("wdm device file gone bad!");
        }

        tv2.tv_sec = 0;
        tv2.tv_usec = sleep_us;
        retval = select(0, NULL, NULL, NULL, &tv2); // sleep
        if (retval == -1)
        {
            throw std::runtime_error(strerror_r(errno, errbuf, SZ));
        }

        retval = select(ctrl+1, &rfds, &wfds, NULL, &tv);
        if (retval == -1)
        {
            throw std::runtime_error(strerror_r(errno, errbuf, SZ));
        }

        if (at_file.bad())
        {
            throw runtime_error("wdm device file gone bad!");
        }

        if (FD_ISSET(ctrl, &wfds))
        {
            cout << "Writing command \'" << command << "\' to ctrl device\n";
            command += "\r";
            at_file << command << endl;
            cout << sendcount++;
        }

        if (FD_ISSET(ctrl, &rfds))
        {
            n = read(ctrl, ctrlin_buf, SZ); // ifstrem::read fails for
some reason
            if (n == -1)
            {
                throw std::runtime_error(strerror_r(errno, errbuf, SZ));
            }
            response = std::string(ctrlin_buf, n);
            cout << response << endl;
        }
    }

    return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to