title: Driver CH341 USB Adapter Serial Port or QSerialPort not Works in Linux
body: <p>The following code works for me correctly in Windows, but Linux does not work. I am using the same PC, both operating systems are installed native. I do not use virtual machine. I need to work on Linux. I have tried in different linux distributions and does not work anywhere.</p>
  
  <pre><code>// In the main class:
  QSerialPortInfo info = XXXX; // Generally in Linux: /dev/ttyUSB0, in win: COM1
  QSerialPort serial;
  QObject::connect(&amp;serial, SIGNAL(readyRead()), this, SLOT(onReadyRead()), Qt::DirectConnection);
  QObject::connect(&amp;serial, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)), Qt::DirectConnection);
  QObject::connect(&amp;serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onError(QSerialPort::SerialPortError)), Qt::DirectConnection);
  
  // Slot
  void MyClass::onReadyRead()
  {
      qDebug()&lt;&lt;"Signal onReadyRead";
      buffer_mutex.lock();
      buffer += serial.readAll();
      qDebug()&lt;&lt;"Read: "&lt;&lt;qstr_to_hexstr(buffer);
      bufferNotEmpty.wakeAll();
      buffer_mutex.unlock();
  }
  
  void MyClass::onError(QSerialPort::SerialPortError error) {
      qCritical()&lt;&lt;"Serial Port Error: "&lt;&lt;(int)error;
  }
  
  void MyClass::onBytesWritten(qint64 size){
      qDebug()&lt;&lt;"onBytesWritten: "&lt;&lt;size;
  }
  
  
  // In another place I did:
  serial.setPort(info); 
  if(!serial.open(QIODevice::ReadWrite))
      return false;
  
  qDebug()&lt;&lt;"Init Setting!...";
  
  if(!serial.setBaudRate(QSerialPort::Baud9600))
      qCritical()&lt;&lt;"Error in setBaudRate";
  if(!serial.setDataBits(QSerialPort::Data8))
      qCritical()&lt;&lt;"Error in setDataBits";
  if(!serial.setParity(QSerialPort::EvenParity))
      qCritical()&lt;&lt;"Error in setParity";
  if(!serial.setStopBits(QSerialPort::OneStop))
      qCritical()&lt;&lt;"Error in setStopBits";
  if(!serial.setFlowControl(QSerialPort::SoftwareControl))
      qCritical()&lt;&lt;"Error in setFlowControl";
  if(!serial.setDataTerminalReady(true))
      qCritical()&lt;&lt;"Error in setDataTerminalReady";
  
  qDebug()&lt;&lt;"Setting ready!...";
  </code></pre>
  
  <p>If sending 1 byte the device responds and sends the data correctly.</p>
  
  <p>Example:</p>
  
  <pre><code>// In the main class:
  const char enq[2] = {0x05, '\0'};
  serial.write (enq);
  
  // In onReadyRead:
  serial.readAll(); // Works on Win / Linux
  </code></pre>
  
  <p>If sent a more than 1 byte device does not respond the request in linux. </p>
  
  <p>Example:</p>
  
  <pre><code>// In the main class:
  const char command[6] = {0x02, 'S', '1', 0x03, 'a', '\0'};
  serial.write(command);
  
  // In onReadyRead
  serial.readAll(); // Works only in Win
  </code></pre>
  
  <p>This event is triggered only in windows. In linux it never works, not received or arrives in bad format and never recognized the remote device.</p>
  
  <p>My log in Windows:</p>
  
  <pre><code>{Debug}         Init Setting!... 
  {Debug}         Setting ready!...
  {Debug}         Write:  " 0x05 "
  {Debug}         onBytesWritten:  1 
  {Debug}         buffer wait!... 
  {Debug}         Signal onReadyRead 
  {Debug}         Read:  " 0x02 `@ 0x03 #" 
  {Debug}         buffer size:  5 
  {Critical}      Serial Port Error:  0 
  {Debug}         Write:  " 0x02 S1 0x03 a" 
  {Debug}         onBytesWritten:  5 
  {Debug}         buffer wait!... 
  {Debug}         Signal onReadyRead 
  {Debug}         Read:  " 0x02 S100 0x0A 00000000000000000 0x0A 00000479" 
  {Debug}         buffer size:  32 
  {Debug}         buffer wait!... 
  {Debug}         Signal onReadyRead 
  {Debug}         Read:  " 0x02 S100 0x0A 00000000000000000 0x0A 00000479 0x0A 00000 0x0A 00000330 0x0A 00000 0x0A 0061 0x0A 0000 0x0A " 
  {Debug}         buffer size:  64 
  {Debug}         Signal onReadyRead 
  {Debug}         buffer wait!... 
  {Debug}         Read:  " 0x02 S100 0x0A 00000000000000000 0x0A 00000479 0x0A 00000 0x0A 00000330 0x0A 00000 0x0A 0061 0x0A 0000 0x0A X-XXXXXXXX 0x0A XXXXXXXXX 0x0A 221715 0x0A 120414 0x0A  0x03  0x1B " 
  {Debug}         buffer size:  103 
  {Critical}      Serial Port Error:  0 
  </code></pre>
  
  <p>(I replace the actual response of the device by the 'X' characters)</p>
  
  <p>My log in Linux:</p>
  
  <pre><code>{Debug}         Init Setting!... 
  {Debug}         Setting ready!...
  {Debug}         Write:  " 0x05 "
  {Debug}         onBytesWritten:  1 
  {Debug}         buffer wait!... 
  {Debug}         Signal onReadyRead 
  {Debug}         Read:  " 0x02 `@ 0x03 #" 
  {Debug}         buffer size:  5 
  {Critical}      Serial Port Error:  0 
  {Debug}         Write:  " 0x02 S1 0x03 a" 
  {Debug}         onBytesWritten:  5 
  {Debug}         buffer wait!... 
  {Debug}         buffer wait!... 
  {Debug}         buffer wait!... 
  {Debug}         buffer wait!... 
  {Debug}         buffer wait!... 
  {Debug}         buffer wait!... 
  {Debug}         buffer wait!... 
  {Debug}         buffer wait!... 
  {Debug}         buffer wait!... 
  {Debug}         buffer wait!... 
  {Debug}         timeout!... (15 sec for timeout)
  </code></pre>
  
  <p>USB Serial Adapter: CH340</p>
  
  <pre><code>In Windows: USB\VID_1A86&amp;PID_7523&amp;REV_0254
  In Linux:
      Apr 13 01:16:58 kali kernel: [47844.260136] usb 2-1: new full-speed USB device number 16 using uhci_hcd
      Apr 13 01:16:58 kali kernel: [47844.428098] usb 2-1: New USB device found, idVendor=1a86, idProduct=7523
      Apr 13 01:16:58 kali kernel: [47844.428115] usb 2-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
      Apr 13 01:16:58 kali kernel: [47844.428126] usb 2-1: Product: USB2.0-Ser!
      Apr 13 01:16:58 kali kernel: [47844.431268] ch341 2-1:1.0: ch341-uart converter detected
      Apr 13 01:16:58 kali kernel: [47844.445398] usb 2-1: ch341-uart converter now attached to ttyUSB0
      Apr 13 01:16:58 kali mtp-probe: checking bus 2, device 16: "/sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1"
      Apr 13 01:16:58 kali mtp-probe: bus: 2, device: 16 was not an MTP device
  </code></pre>
  
  <p>PD: Sorry for my English, try to do my best with Google Translator :(...</p>
  
  <p><strong>More information 1:</strong></p>
  
  <pre><code>Apr 13 04:10:55 kali kernel: [ 4872.627980] tty ttyUSB0: serial_write - 1 byte(s)
  Apr 13 04:10:55 kali kernel: [ 4872.629763] tty ttyUSB0: serial_chars_in_buffer
  Apr 13 04:10:55 kali kernel: [ 4872.629778] tty ttyUSB0: serial_wait_until_sent
  Apr 13 04:10:55 kali kernel: [ 4872.638252] tty ttyUSB0: serial_chars_in_buffer
  Apr 13 04:10:55 kali kernel: [ 4872.638267] tty ttyUSB0: serial_write_room
  Apr 13 04:10:55 kali kernel: [ 4872.638278] tty ttyUSB0: serial_chars_in_buffer
  Apr 13 04:10:55 kali kernel: [ 4872.638287] tty ttyUSB0: serial_write_room
  Apr 13 04:10:55 kali kernel: [ 4872.639438] tty ttyUSB0: serial_chars_in_buffer
  Apr 13 04:10:55 kali kernel: [ 4872.639458] tty ttyUSB0: serial_write_room
  Apr 13 04:10:55 kali kernel: [ 4872.639475] tty ttyUSB0: serial_chars_in_buffer
  Apr 13 04:10:55 kali kernel: [ 4872.639488] tty ttyUSB0: serial_write_room
  Apr 13 04:10:56 kali kernel: [ 4873.641799] tty ttyUSB0: serial_ioctl - cmd 0x540b
  Apr 13 04:10:56 kali kernel: [ 4873.646884] tty ttyUSB0: serial_write - 5 byte(s)
  Apr 13 04:10:56 kali kernel: [ 4873.647152] ch341-uart ttyUSB0: ch341_update_line_status - multiple status change
  Apr 13 04:10:56 kali kernel: [ 4873.647176] ch341-uart ttyUSB0: ch341_update_line_status - delta=0x01
  Apr 13 04:10:56 kali kernel: [ 4873.647384] tty ttyUSB0: serial_chars_in_buffer
  Apr 13 04:10:56 kali kernel: [ 4873.647401] tty ttyUSB0: serial_wait_until_sent
  Apr 13 04:10:56 kali kernel: [ 4873.649144] ch341-uart ttyUSB0: ch341_update_line_status - multiple status change
  Apr 13 04:10:56 kali kernel: [ 4873.649166] ch341-uart ttyUSB0: ch341_update_line_status - delta=0x01
  Apr 13 04:10:56 kali kernel: [ 4873.692152] ch341-uart ttyUSB0: ch341_update_line_status - multiple status change
  Apr 13 04:10:56 kali kernel: [ 4873.692170] ch341-uart ttyUSB0: ch341_update_line_status - delta=0x01
  Apr 13 04:10:56 kali kernel: [ 4873.694133] ch341-uart ttyUSB0: ch341_update_line_status - multiple status change
  Apr 13 04:10:56 kali kernel: [ 4873.694148] ch341-uart ttyUSB0: ch341_update_line_status - delta=0x01
  </code></pre>
  
  <p>I rebuild ch341.c and add:</p>
  
  <pre><code>if (!delta)
      return;
  
  dev_info(&amp;port-&gt;dev, "%s - delta=0x%02X\n", __func__, delta); // &lt;---- New Line
  
  if (delta &amp; CH341_BIT_CTS)
      port-&gt;icount.cts++;
  if (delta &amp; CH341_BIT_DSR)
      port-&gt;icount.dsr++;
  if (delta &amp; CH341_BIT_RI)
      port-&gt;icount.rng++;
  if (delta &amp; CH341_BIT_DCD) {
      port-&gt;icount.dcd++;
      tty = tty_port_tty_get(&amp;port-&gt;port);
      if (tty) {
          usb_serial_handle_dcd_change(port, tty,
                      status &amp; CH341_BIT_DCD);
          tty_kref_put(tty);
      }
  }
  </code></pre>
  
  <p>delta=0x01 in the log is flag: </p>
  
  <pre><code>#define CH341_BIT_CTS 0x01
  </code></pre>
  
  <p><strong>More information 2:</strong></p>
  
  <p>In the thread of write / read I hope for wakeAll, running on onReadyRead. If you pass a second make a readAll before checking if the buffer is empty. example:</p>
  
  <pre><code>// In the main class:
  QWaitCondition bufferNotEmpty;
  
  // In my function write/read:
  serial.write(data, size);
  buffer_mutex.lock();
  while(time(NULL)-timeStart&lt;timeoutWait &amp;&amp; serial.isOpen()) {
      buffer += serial.readAll();
      if(buffer.count()&gt;0){
          qDebug()&lt;&lt;"buffer size: "&lt;&lt;buffer.count();
          //Interprete the buffer here...
  
          if(bufferComplete) 
              break;
      }
      qDebug()&lt;&lt;"buffer wait!...";
      bufferNotEmpty.wait(&amp;buffer_mutex, 1000);
  }
  buffer.clear();
  buffer_mutex.unlock();
  </code></pre>
  
  <p><strong>More information 3:</strong></p>
  
  <p>My Kernel is 3.12.6, but i updated from GitHub this file an rebuild this drivers: </p>
  
  <p><a href="https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c" rel="noreferrer">https://github.com/torvalds/linux/blob/master/drivers/usb/serial/ch341.c</a> 
  <a href="https://github.com/torvalds/linux/blob/master/drivers/usb/serial/usb-serial.c" rel="noreferrer">https://github.com/torvalds/linux/blob/master/drivers/usb/serial/usb-serial.c</a> 
  (commit d9a38a8741fdffabc32e6d0943b1cdcf22712bec) </p>