[Epic 4G Android Development] mkasick:
2/22/11 Update: Froyo kernels include tethering support, so this patch is no longer necessary. A Froyo-compatible Wired Tether client is available here.

12/20/10 Update: Added patch to wired-tether client to clamp MSS. Fixes stalled connections when the network breaks fragmentation support.

10/18/10 Update: The MixUp-20101024-847 kernel now includes USB tethering (RNDIS) support. If you have this kernel installed, you should be able to USB tether by installing the modified android-wired-tether client attached here.

Troubleshooting Update: If the client force closes on you and you're using a ROM with android-wifi-tether preinstalled, then there is a library conflict. Remove android-wifi-tether from /system, and most importantly, delete (or rename) /system/lib/libnativetask.so, then android-wired-tether should work. If you want both wifi & wired tether, reinstall android-wifi-tether from the market. This will make each application use its own library so there's no more conflicts. See this post for more details.

Attached is a patch to the DI18 kernel sources to enable USB tethering support with android-wired-tether. Kernel developers, please feel free to include this patch in your kernel builds. It requires no configuration changes.

This patch requires use of a modified wired-tether agent (at least, until the change is commited upstream). A modified build of wired-tether is also attached, along with the source patches against upstream v1.4 (SVN r34).

Also attached is a build of the stock DI18 kernel with the kerel patch applied. It's compiled with CodeSourcery Lite 2009q3-68 with stock config options, stock initramfs (so no root, no clockworkmod support). It's intended for folks who want to try this right away, and know how to restore their old kernel if need be.

Directions:

To install the test kernel, look for a copy of redbend_ua in any of the kernel update.zip packages, install with:

adb push redbend_ua /data/local/tmp
adb push zImage /sdcard
adb shell
su
chmod 755 /data/local/tmp/redbend_ua
/data/local/tmp/redbend_ua restore /sdcard/zImage /dev/block/bml7

Then install the attached wired-tether-1.4-epic-2.apk. Tethering may be used with "USB debugging" enabled or disabled. However, neither mass-storage support nor ADB will be availble while actively tethering. To use:

(Windows only) Install the Samsung USB drivers. No other drivers are needed for Windows 7, and I think Windows XP SP3.

Make sure the USB cable is unplugged before starting the tether client.

Start "Wired Tether" and "Press to start tethering."

Grant the Superuser Request (if your su requires it).

Make sure tethering has started, you should see green/red "Down/Up" numbers at the bottom of the screen.

Attach the USB cable.

Select "Charging" mode if the "Select USB mode" menu comes up (it won't if USB debugging is enabled).

Tether!

When finished:

Detach the USB cable.

"Press to stop tethering."

Grant the Superuser Request (if your su requires it).

Exit the "Wired Tether" program.

Reattach the USB cable if you want to use mass-storage or ADB.

Technical details (for those interested, otherwise ignore):

The Epic kernel already provides RNDIS USB support in the USB gadget driver, however the host-side RNDIS interface is never presented. The kernel patch adds a sysfs variable that, when enabled, configures the host-side USB to exlusively present the RNDIS interfaces, and when disabled, reconfigures the host-side USB back to the previous state, either mass-storage (actually typically "KIES" mode) or ADB. You may toggle this variable manually, for example, if you wanted to use the RNDIS interface for other purposes. Just be sure to toggle when the USB cable is unplugged:

su
echo -n 1 > /sys/devices/virtual/sec/switch/rndis_enable # Enable RNDIS.
echo -n 0 > /sys/devices/virtual/sec/switch/rndis_enable # Disable RNDIS, reenable UMS or ADB.

The wired-tether patch simply toggles the sysfs varible upon starting and stopping tethering. Since the host-side USB interface will only reconfigure upon cable reinsertion (I think?), this is why the cable must be attached/detached only while tethering is enabled.

Note that the host-side RNDIS interface is exclusively presented--it may not be used simultaneously with mass-storage or ADB. This is a limitation of the Samsung Windows driver and will not be fixed. The previous version of the kernel patch (10/8) did present RNDIS alongside ADB, which is a mode of operation generally supported by Linux. However, the Samsung drivers need to be modified to support this mode (necessitating a reinstall) and as it turns out, driver bugs presents the along-side configuration from actually working. Because of this, and reports from Ubuntu users of losing ADB with the previous version, this patch only uses "blessed" host-side USB configurations.

Nitty grity details:

I'm not precisely sure what "Tethered Mode" is, that shows up in the menu when you plug in a USB cable with debugging disabled. From the USB gadget driver code, it appears to disconnect one (or both) of the 3G/4G modems and presents it over the USB interface directly, not allowing it to be shared with the phone. This may use the RNDIS interface (hence why it's "supported" in the first place), or may expose a serial UART. I've never tried it, and I'm uncertain (from the driver code) that it actually works.

Amusingly enough, it should be possible to enable the RNDIS interface even with the stock kernel. However, the gadget driver code is very buggy, and the existing sysfs interfaces do not operate as advertised. Even if you "game the bugs" to work around them, you'll lose ADB support until the phone is restarted. Since I would have to modify the kernel to fix these bugs, I decided to just present a new interface that mirrors the behavior of ADB mode, to keep the patch simple to maintain.

If you want to follow along though, the two relevant parts of the USB gadget driver are "adb_ums_acm_mtp_rndis.c" and "fsa9480_i2c.c" (in "drivers/usb/gadget"). "adb_ums_acm_mtp_rndis.c" contains host-side USB interface configurations for UMS mode (default), ACM/UMS/ADB (USB debugging), ACM/MTP (disabled), MTP (disabled), RNDIS (basically unused), and ACM only (disabled). The two functions that appear to switch between configurations are enable_adb() and enable_askon().

At first I thought enable_adb() was used by "USB debugging" mode, and enable_askon() by the "Charging/Mass Storage/Tethered Mode" menu, but this isn't the case. Turns out enable_adb() is the only of the two actually used, and enable_askon() is buggy dead code that, for example, doesn't set the current USB configuration status so it's not possible to switch back to the previous configuration.

"fsa9480_i2c.c" contains, among other things, a variety of show/store functions exported as (world-writeable!) sysfs variables in /sys/devices/virtual/sec/switch. I can't tell if these were intended for internal debugging only, or if they were intended to be used by userspace (e.g., the "Select USB mode" menu). The two interesting interfaces here are UsbMenuSel and AskOnMenuSel, which should take a USB device configuration nickname (e.g., "UMS", "KIES", "VTP") and set the host-side USB configuration accordingly. However, the "if/else if/else" lists in both functions are broken, and the "else" clause is often executed when it shouldn't. Interestingly enough, the default host-side USB mode appears to be "KIES", although I'm unsure if that's intentional or due to this bug. But this doesn't matter since the ACM/MTP configuration is disabled and UMS is used in its place.

In other words, the USB gadget driver code is a misleading rats nest of buggy/dead code. It's a wonder it actually works in the first place. I really hope the rest of the device-specific code isn't that bad, but I'm afraid to look.

Mirror links (does not require forum login):

kernel_rndis_enable.diff

kernel_rndis_enable.zip

wired-tether-1.4-epic-2.apk

wired-tether_use_stable_api.diff

wired-tether_clamp_mss.diff

wired-tether_rndis_enable.diff