Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use Samsung S6812B on linux #286

Open
j-alonso opened this issue Aug 22, 2015 · 5 comments
Open

Can't use Samsung S6812B on linux #286

j-alonso opened this issue Aug 22, 2015 · 5 comments

Comments

@j-alonso
Copy link

The current git version of Heimdall cannot access my device.
The device in ODIN mode have VID:PID: 04E8:685D

Investigating this, I found:
During the process of initialization, the device accepts configuration
requests from the host computer.
When this process finishes, the device enters a state waiting ONLY for
handshake "ODIN" "LOKE". Any other request will fail and lock the
device in a error state.
diagram2

PROBLEMS:

  1. ModemManager.
    The ModemManager send configuration requests to the USB
    causing the lock of the device.

    To avoid this, the ModemManager can be deactivated before connecting the
    USB cable: su -c "systemctl stop ModemManager"
    Or the device can be blacklisted for the ModemManager.

  2. Heimdall
    The call of libusb_set_interface_alt_setting send configuration requests
    causing the lock of the device.
    Suggestion: do not use libusb_set_interface_alt_setting.
    Since there is only one altsetting, I think is not necessary
    to call this function (need to investigate more!).
    The call of libusb_get_string_descriptor_ascii send configuration requests
    causing the lock of the device.
    Suggestion: do not use.


Simple quick fix: (only comment out source)

diff --git a/heimdall/source/BridgeManager.cpp b/heimdall/source/BridgeManager.cpp
index b7bff3d..4bd4042 100644
--- a/heimdall/source/BridgeManager.cpp
+++ b/heimdall/source/BridgeManager.cpp
@@ -128,23 +128,23 @@ int BridgeManager::FindDeviceInterface(void)
    {
        unsigned char stringBuffer[128];

-       if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iManufacturer,
-           stringBuffer, 128) >= 0)
-       {
-           Interface::Print("      Manufacturer: \"%s\"\n", stringBuffer);
-       }
-
-       if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iProduct,
-           stringBuffer, 128) >= 0)
-       {
-           Interface::Print("           Product: \"%s\"\n", stringBuffer);
-       }
-
-       if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iSerialNumber,
-           stringBuffer, 128) >= 0)
-       {
-           Interface::Print("         Serial No: \"%s\"\n", stringBuffer);
-       }
+//     if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iManufacturer,
+//         stringBuffer, 128) >= 0)
+//     {
+//         Interface::Print("      Manufacturer: \"%s\"\n", stringBuffer);
+//     }
+//
+//     if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iProduct,
+//         stringBuffer, 128) >= 0)
+//     {
+//         Interface::Print("           Product: \"%s\"\n", stringBuffer);
+//     }
+//
+//     if (libusb_get_string_descriptor_ascii(deviceHandle, deviceDescriptor.iSerialNumber,
+//         stringBuffer, 128) >= 0)
+//     {
+//         Interface::Print("         Serial No: \"%s\"\n", stringBuffer);
+//     }

        Interface::Print("\n            length: %d\n", deviceDescriptor.bLength);
        Interface::Print("      device class: %d\n", deviceDescriptor.bDeviceClass);
@@ -261,13 +261,13 @@ bool BridgeManager::SetupDeviceInterface(void)
 {
    Interface::Print("Setting up interface...\n");

-   int result = libusb_set_interface_alt_setting(deviceHandle, interfaceIndex, altSettingIndex);
+// int result = libusb_set_interface_alt_setting(deviceHandle, interfaceIndex, altSettingIndex);

-   if (result != LIBUSB_SUCCESS)
-   {
-       Interface::PrintError("Setting up interface failed!\n");
-       return (false);
-   }
+// if (result != LIBUSB_SUCCESS)
+// {
+//     Interface::PrintError("Setting up interface failed!\n");
+//     return (false);
+// }

    Interface::Print("\n");
    return (true);
@j-alonso
Copy link
Author

Complementing the report, the test sequence used was:

  • Put the device in Power off state, no USB cable.

  • Press and hold Power, Volume Down and Home.

  • Wait for a Warning screen and release de keys.

  • Follow the screen intructions and click Volume UP.

  • Now the device is in "ODIN Mode" and is in "INITIAL STATE".

  • Start wireshark to see the Usb commands over the cable.

  • Plug the Usb cable to the computer.

  • The Usb sub-system senses a new device and will
    send commands to identify the device:

    • Get Descriptor Request Device
    • Get Descriptor Request Configuration
    • Get Descriptor Request String
    • Set Configuration Request
    • Set Line Coding Request

    The device responds correctly.

  • At this point the device is in "Initial Handshake" (see figure).

  • If the ModemManager is present and the device is not blacklisted
    then:
    It will try identify the device to see if its a modem and
    will send configuration requests over the cable.
    These requests lock the device in "ERROR STATE".

  • Heimdall sequence of calls to libusb:

    • libusb_get_device_list (A)
    • libusb_free_device_list (A)
    • libusb_get_device_descriptor (A)
    • libusb_get_string_descriptor_ascii (B)
    • libusb_get_config_descriptor (A)
    • libusb_free_config_descriptor (A)
    • libusb_claim_interface (A)
    • libusb_set_interface_alt_setting (B)
    • SendBulkTransfer ---> ODIN

    The calls marked with (A) use information cached in the
    system and do not send commands over the cable.
    The calls marked with (B) send commands over the cable and
    lock the device in "ERROR STATE".

When the device enters "ERROR STATE" it responds with:
URB status: No such file or directory (-ENOENT) -2
The device must be powered off to be used again.

fedora 22
kernel-4.1.4-200.fc22.x86_64
libusbx-1.0.19-2.fc22.x86_64
libusbx-devel-1.0.19-2.fc22.x86_64

@villavic
Copy link

This is the correct RCA of all the reported issues on error 110 and similar for many devices.
Running off master it can be easily tested by only commenting out the set_interface_alt_setting call and running without --verbose (as get_string_descriptor_ascii locks the device and now it's only called when running with --verbose).
As an alternative to just removing that piece of code, I just put an

    if (altSettingIndex == 0)
        return (true);

before set_interface_alt_setting, instead.
Tested on Gentoo running kernel 4.3.3 and libusb-1.0.20 against a Samsung GT-S5367.

@jkkoski
Copy link

jkkoski commented Dec 31, 2015

I can confirm that this works with Samsung Galaxy Trend Plus (GT-S7580).

@j-alonso
Copy link
Author

j-alonso commented Jan 4, 2016

Investigating at source level (libusb and kernel usb), I found:

Linux kernel have a module called "cdc_acm" that is automatically
called when the Samsung Mobile Phone in ODIN mode is plugged.
This module is used for USB modems and ISDN adapters. It creates
a character device /dev/ttyACM* and sends "Set Line Coding" to the
device. Then a system service called ModemManager run on /dev/ttyACM*
to provide unified high level API for communicating with the modem.

I suppose that all Samsung Mobile Phones in ODIN mode are recognized
as "CDC ACM" and the module "cdc_acm" is always called.
To verify this for your phone check the system log for a line with:
"cdc_acm 2-1.2:1.0: ttyACM0: USB ACM device"

Note: "Set Line Coding" is not sent when the module "cdc_acm" is not
called and Heimdall uses "libusb".

Problem:
All phones in ODIN mode receive the command "Set Line Coding", but
only a subset (GT-S6812B, GT-S5367, GT-S7580 ...) locks if some "libusb"
calls are called like:
libusb_set_interface_alt_setting and libusb_get_string_descriptor_ascii.
These are described in more detail at the start of the thread.

The devices not affected by "Set Line Coding" can have problems with
ModemManager. Depending of timing, ModemManager can run simultaneously
with Heimdall. See @kynan comment in issue #228. He propose a "blacklist"
for ModemManager.

I think that a solution would be:

Blacklist the Samsung devices in ODIN mode in the module "cdc_acm".
I send patches to the maintainer of cdc_acm to blacklist the 3 devices used:

http://marc.info/?l=linux-usb&m=145185842102902&w=2
@Benjamin-Dobell There is a problem with 2 devices. Do you have more
information about these devices?

This solution works for new kernels.
Since there is no ttyACM device, there is no problem with ModemManager.

For old kernels, the user can temporarily blacklist the module "cdc_acm"
using this instructions:

I think that a solution would be:

The user can temporarily blacklist the module "cdc_acm"
using this instructions:

  • Put the device in ODIN mode (no USB cable)
  • Execute the commands as root:
  echo "blacklist cdc_acm" >/etc/modprobe.d/cdc_acm-blacklist.conf
  rmmod cdc_acm  # ignore ERROR is not currently loaded
  • Plug the USB cable and use heimdall.
  • At the end remove the file /etc/modprobe.d/cdc_acm-blacklist.conf

Note: Since there is no ttyACM device, there is no problem with ModemManager.

@villavic
Copy link

There is no need to mess around with the cdc_acm module and ModemManager. There's a proper method to make ModemManager ignore an interface and that is setting:

ENV{ID_MM_DEVICE_IGNORE}="1"

in the udev rule for the devices. Heimdall already installs such an udev rule to set the permissions of the device's character files in /dev , it's just a matter of adding this, such as:

SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", ATTR{idProduct}=="685d", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"

At least on my testing, with the previously mentioned changes (skipping set_interface_alt_setting and running without --verbose) having both ModemManager running and cdc_acm loaded doesn't affect Heimdall flashing at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants