diff --git a/lib/xebow/hid_gadget.ex b/lib/xebow/hid_gadget.ex index 5b46760..ae3fe70 100644 --- a/lib/xebow/hid_gadget.ex +++ b/lib/xebow/hid_gadget.ex @@ -22,16 +22,14 @@ defmodule Xebow.HIDGadget do # :os.cmd('mount -t configfs none /sys/kernel/config') # Set up gadget devices using configfs - case create_rndis_ecm_hid("hidg") do - :ok -> - # Make sure we clear out any existing gadget configuration. - # :os.cmd('rmmod g_cdc') - USBGadget.disable_device("hidg") - - USBGadget.enable_device("hidg") - setup_bond0() - {:ok, :ok} + hid_device_name = "hidg" + with :ok <- create_ncm_rndis_hid(hid_device_name), + :ok <- USBGadget.disable_device(hid_device_name), + :ok <- USBGadget.enable_device(hid_device_name), + :ok <- setup_bond0() do + {:ok, :ok} + else error -> Logger.warn("Error setting up USB gadgets: #{inspect(error)}") {:ok, error} @@ -46,7 +44,7 @@ defmodule Xebow.HIDGadget do # GenServer.call(__MODULE__, :status) # end - defp create_rndis_ecm_hid(name) do + defp create_ncm_rndis_hid(name) do device_settings = %{ "bcdUSB" => "0x0200", "bDeviceClass" => "0xEF", @@ -107,25 +105,27 @@ defmodule Xebow.HIDGadget do "MaxPower" => "500", "strings" => %{ "0x409" => %{ - "configuration" => "RNDIS and ECM Ethernet with HID Keyboard" + "configuration" => "NCM and RNDIS Ethernet with HID Keyboard" } } } - function_list = ["rndis.usb0", "ecm.usb1", "hid.usb2"] + function_list = ["rndis.usb0", "ncm.usb1", "hid.usb2"] with {:create_device, :ok} <- {:create_device, USBGadget.create_device(name, device_settings)}, {:create_rndis, :ok} <- {:create_rndis, USBGadget.create_function(name, "rndis.usb0", rndis_settings)}, - {:create_ecm, :ok} <- {:create_ecm, USBGadget.create_function(name, "ecm.usb1", %{})}, + {:create_ncm, :ok} <- + {:create_ncm, USBGadget.create_function(name, "ncm.usb1", %{})}, {:create_hid, :ok} <- {:create_hid, USBGadget.create_function(name, "hid.usb2", hid_settings)}, {:create_config, :ok} <- {:create_config, USBGadget.create_config(name, "c.1", config1_settings)}, {:link_functions, :ok} <- {:link_functions, USBGadget.link_functions(name, "c.1", function_list)}, - {:link_os_desc, :ok} <- {:link_os_desc, USBGadget.link_os_desc(name, "c.1")} do + {:link_os_desc, :ok} <- + {:link_os_desc, USBGadget.link_os_desc(name, "c.1")} do :ok else {failed_step, {:error, reason}} -> {:error, {failed_step, reason}} @@ -134,17 +134,39 @@ defmodule Xebow.HIDGadget do defp setup_bond0 do # Set up the bond0 interface across usb0 and usb1. - # In the rndis_ecm_acm pre-defined device being used here, usb0 is the - # RNDIS (Windows-compatible) device and usb1 is the ECM - # (non-Windows-compatible) device. - # Since Linux supports both with ECM being more reliable, we set usb1 (ECM) - # as the primary, meaning that it will be used if both are available. - System.cmd("ip", ["link", "set", "bond0", "down"]) - File.write("/sys/class/net/bond0/bonding/mode", "active-backup") - File.write("/sys/class/net/bond0/bonding/miimon", "100") - File.write("/sys/class/net/bond0/bonding/slaves", "+usb0") - File.write("/sys/class/net/bond0/bonding/slaves", "+usb1") - File.write("/sys/class/net/bond0/bonding/primary", "usb1") - System.cmd("ip", ["link", "set", "bond0", "up"]) + # In the pre-defined device being used here, usb0 is the + # RNDIS (Windows-compatible) device, usb1 is the NCM (Mac OS Catalina-compatible). + # Since Linux supports both, with NCM being more reliable, we set + # usb1 (NCM) as the primary, meaning that it will be used if all are available. + bond0_sys_directory = "/sys/class/net/bond0/bonding" + exit_success = 0 + + with {_, ^exit_success} <- set_bond0_link_state(:down), + :ok <- write_file(bond0_sys_directory, "mode", "active-backup"), + :ok <- write_file(bond0_sys_directory, "miimon", "100"), + :ok <- write_file(bond0_sys_directory, "slaves", "+usb0"), + :ok <- write_file(bond0_sys_directory, "slaves", "+usb1"), + :ok <- write_file(bond0_sys_directory, "primary", "usb1"), + {_, ^exit_success} <- set_bond0_link_state(:up) do + :ok + else + {:error, reason} -> {:error, reason} + end + end + + defp set_bond0_link_state(state) when state in [:up, :down] do + state = to_string(state) + + try do + System.cmd("ip", ["link", "set", "bond0", state]) + rescue + reason -> {:error, reason} + end + end + + defp write_file(base_directory, filename, data) do + base_directory + |> Path.join(filename) + |> File.write(data) end end diff --git a/mix.exs b/mix.exs index c48b154..8383c04 100644 --- a/mix.exs +++ b/mix.exs @@ -109,7 +109,7 @@ defmodule Xebow.MixProject do # Dependencies for specific targets {:nerves_system_keybow, github: "ElixirSeattle/nerves_system_keybow", - ref: "v1.12.1+keybow.1", + ref: "v1.12.1+keybow.2", runtime: false, targets: :keybow} ] diff --git a/mix.lock b/mix.lock index eac3bb3..fa4667f 100644 --- a/mix.lock +++ b/mix.lock @@ -30,12 +30,13 @@ "nerves_pack": {:hex, :nerves_pack, "0.3.1", "ad725eaa061c7419dd9dbbb0b4e975ac7b0ed59368c98158bf7a90764726d868", [:mix], [{:mdns_lite, "~> 0.6", [hex: :mdns_lite, repo: "hexpm", optional: false]}, {:nerves_firmware_ssh, "~> 0.4", [hex: :nerves_firmware_ssh, repo: "hexpm", optional: false]}, {:nerves_runtime, "~> 0.6", [hex: :nerves_runtime, repo: "hexpm", optional: false]}, {:nerves_time, "~> 0.3", [hex: :nerves_time, repo: "hexpm", optional: false]}, {:ring_logger, "~> 0.8", [hex: :ring_logger, repo: "hexpm", optional: false]}, {:vintage_net, "~> 0.7.0 or ~> 0.8.0", [hex: :vintage_net, repo: "hexpm", optional: false]}, {:vintage_net_direct, "~> 0.7", [hex: :vintage_net_direct, repo: "hexpm", optional: false]}, {:vintage_net_ethernet, "~> 0.7", [hex: :vintage_net_ethernet, repo: "hexpm", optional: false]}, {:vintage_net_wifi, "~> 0.7", [hex: :vintage_net_wifi, repo: "hexpm", optional: false]}], "hexpm", "5f343308fd101e6e4ff1ac79be220d6aa9efb6b560131f6fd30b0e6d2f57ead9"}, "nerves_runtime": {:hex, :nerves_runtime, "0.11.2", "7606c559d6eb33736af813394d8b4e67e3ede155808c6dc4b2ac0aea2c1b66fb", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:system_registry, "~> 0.8.0", [hex: :system_registry, repo: "hexpm", optional: false]}, {:uboot_env, "~> 0.1.1 or ~> 0.2.0", [hex: :uboot_env, repo: "hexpm", optional: false]}], "hexpm", "094446be5a1d51d3ec0c26e9f5905ab42731397e8715404a5e5e095b4f3125b6"}, "nerves_system_br": {:hex, :nerves_system_br, "1.12.0", "e86a6fc34c28b667ff2b7b614c23b7c3bc00c253165e6cb41d76bd4e3d1bbc36", [:mix], [], "hexpm", "572ff3e540677b1addb70b8fd2a6652a372a7eb1a961722c7954dffa065f267c"}, - "nerves_system_keybow": {:git, "https://github.com/ElixirSeattle/nerves_system_keybow.git", "1ef277a87447582a4db32bc50655efcab5445b94", [ref: "v1.12.1+keybow.1"]}, + "nerves_system_keybow": {:git, "https://github.com/ElixirSeattle/nerves_system_keybow.git", "55f3efdcd30e1e573eb1e05bf9965a62f2540d60", [ref: "v1.12.1+keybow.2"]}, "nerves_system_linter": {:hex, :nerves_system_linter, "0.3.0", "84e0f63c8ac196b16b77608bbe7df66dcf352845c4e4fb394bffd2b572025413", [:mix], [], "hexpm", "bffbdfb116bc72cde6e408c34c0670b199846e9a8f0953cc1c9f1eea693821a1"}, "nerves_time": {:hex, :nerves_time, "0.4.1", "b9fa73af7592f9fa7bad32f2c8ae655f9209dbc67f534c4f0532ec354a95dd7a", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:muontrap, "~> 0.5", [hex: :muontrap, repo: "hexpm", optional: false]}], "hexpm", "1683db2cb7b3f2d04e9a259b2a3bbd3a9ae534ddff5ee81ae71f3c8a59b25224"}, "nerves_toolchain_armv6_rpi_linux_gnueabi": {:hex, :nerves_toolchain_armv6_rpi_linux_gnueabi, "1.3.2", "beb0f97d6f432406af6c4fdcee02d2ab750298845834f869a0b98239362783ae", [:mix], [{:nerves, "~> 1.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_toolchain_ctng, "~> 1.7.2", [hex: :nerves_toolchain_ctng, repo: "hexpm", optional: false]}], "hexpm", "ef93b7d678241be2d4520dceecf6a2116bb87640576211dad3b618ce79b85e39"}, "nerves_toolchain_ctng": {:hex, :nerves_toolchain_ctng, "1.7.2", "0683dff3b81483879a57e14d8e020314a4d1ecc6ee91952c1d7d9f1f528924a4", [:mix], [{:nerves, "~> 1.0", [hex: :nerves, repo: "hexpm", optional: false]}], "hexpm", "5d44f279705119defac7f28a70edb0273f92b38bc8ae668db4f271cd91f6eaee"}, "nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"}, + "observer_cli": {:hex, :observer_cli, "1.5.4", "e8489b3a7c77c2155c0b67fa9f90d9afa76bf15c24fb7b312addcc117771d154", [:mix, :rebar3], [{:recon, "~>2.5.1", [hex: :recon, repo: "hexpm", optional: false]}], "hexpm", "f4825d374b22f258ad114a74796b79b86e20a03611051719f6062353c05389cb"}, "one_dhcpd": {:hex, :one_dhcpd, "0.2.4", "2664f2e1ac72cbae0474a88d1a3d55019ccc3ee582ded382589511627a8ed516", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "38f08c228d066153dbe352b150910345e395eacd2db3c19085d54c0baeeebacb"}, "phoenix": {:hex, :phoenix, "1.5.3", "bfe0404e48ea03dfe17f141eff34e1e058a23f15f109885bbdcf62be303b49ff", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8e16febeb9640d8b33895a691a56481464b82836d338bb3a23125cd7b6157c25"}, "phoenix_html": {:hex, :phoenix_html, "2.14.2", "b8a3899a72050f3f48a36430da507dd99caf0ac2d06c77529b1646964f3d563e", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "58061c8dfd25da5df1ea0ca47c972f161beb6c875cd293917045b92ffe1bf617"}, @@ -47,6 +48,7 @@ "plug_cowboy": {:hex, :plug_cowboy, "2.3.0", "149a50e05cb73c12aad6506a371cd75750c0b19a32f81866e1a323dda9e0e99d", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bc595a1870cef13f9c1e03df56d96804db7f702175e4ccacdb8fc75c02a7b97e"}, "plug_crypto": {:hex, :plug_crypto, "1.1.2", "bdd187572cc26dbd95b87136290425f2b580a116d3fb1f564216918c9730d227", [:mix], [], "hexpm", "6b8b608f895b6ffcfad49c37c7883e8df98ae19c6a28113b02aa1e9c5b22d6b5"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"}, + "recon": {:hex, :recon, "2.5.1", "430ffa60685ac1efdfb1fe4c97b8767c92d0d92e6e7c3e8621559ba77598678a", [:mix, :rebar3], [], "hexpm", "5721c6b6d50122d8f68cccac712caa1231f97894bab779eff5ff0f886cb44648"}, "ring_logger": {:hex, :ring_logger, "0.8.0", "b1baddc269099b2afe2ea3a87b8e2b71e57331c0000038ae55090068aac679db", [:mix], [], "hexpm", "9b2f482e4346c13c11ef555f898202d0ddbfda6e2354e5c6e0559d2b4e0cf781"}, "shoehorn": {:hex, :shoehorn, "0.6.0", "f9a1b7d6212cf18ba91c4f71c26076059df33cea4db2eb3c098bfa6673349412", [:mix], [{:distillery, "~> 2.1", [hex: :distillery, repo: "hexpm", optional: true]}], "hexpm", "e54a1f58a121caf8f0f3a355686b2661258b1bc0d4fffef8923bd7b11c2f9d79"}, "socket": {:hex, :socket, "0.3.13", "98a2ab20ce17f95fb512c5cadddba32b57273e0d2dba2d2e5f976c5969d0c632", [:mix], [], "hexpm", "f82ea9833ef49dde272e6568ab8aac657a636acb4cf44a7de8a935acb8957c2e"},