/* Copyright 2019-2020 Dmitry Isaenko This file is part of NS-USBloader. NS-USBloader is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. NS-USBloader is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with NS-USBloader. If not, see . */ package nsusbloader.com.usb; import nsusbloader.ModelControllers.ILogPrinter; import nsusbloader.NSLDataTypes.EMsgType; import org.usb4java.*; public class UsbConnect { private static final int DEFAULT_INTERFACE = 0; private static final int DEFAULT_HOMEBREW_CONFIGURATION = 1; private static final short RCM_VID = 0x0955; private static final short RCM_PID = 0x7321; private static final short HOMEBREW_VID = 0x057E; private static final short HOMEBREW_PID = 0x3000; // private static final short TEST_VID = 0x1a86; // private static final short TEST_PID = 0x7523; private Context contextNS; private DeviceHandle handlerNS; private Device deviceNS; private ILogPrinter logPrinter; private boolean connected; // TODO: replace to 'connectionFailure' and invert requests everywhere private short VENDOR_ID; private short PRODUCT_ID; private int returningValue; private DeviceList deviceList; public static UsbConnect connectRcmMode(ILogPrinter logPrinter){ UsbConnect usbConnect = new UsbConnect(logPrinter); usbConnect.VENDOR_ID = RCM_VID; usbConnect.PRODUCT_ID = RCM_PID; try{ usbConnect.createContextAndInitLibUSB(); usbConnect.getDeviceList(); usbConnect.findDevice(); usbConnect.openDevice(); usbConnect.freeDeviceList(); usbConnect.setAutoDetachKernelDriver(); //this.resetDevice(); usbConnect.claimInterface(); usbConnect.connected = true; } catch (Exception e){ try { logPrinter.print(e.getMessage(), EMsgType.FAIL); } catch (InterruptedException ignore){} usbConnect.close(); } return usbConnect; } public static UsbConnect connectHomebrewMode(ILogPrinter logPrinter){ UsbConnect usbConnect = new UsbConnect(logPrinter); usbConnect.VENDOR_ID = HOMEBREW_VID; usbConnect.PRODUCT_ID = HOMEBREW_PID; try { usbConnect.createContextAndInitLibUSB(); usbConnect.getDeviceList(); usbConnect.findDevice(); usbConnect.openDevice(); usbConnect.freeDeviceList(); usbConnect.setAutoDetachKernelDriver(); //this.resetDevice(); usbConnect.setConfiguration(DEFAULT_HOMEBREW_CONFIGURATION); usbConnect.claimInterface(); usbConnect.connected = true; } catch (Exception e){ e.printStackTrace(); try { logPrinter.print(e.getMessage(), EMsgType.FAIL); } catch (InterruptedException ignore){} usbConnect.close(); } return usbConnect; } private UsbConnect(){} private UsbConnect(ILogPrinter logPrinter){ this.logPrinter = logPrinter; this.connected = false; } private void createContextAndInitLibUSB() throws Exception{ // Creating Context required by libusb. Optional? Consider removing. contextNS = new Context(); returningValue = LibUsb.init(contextNS); if (returningValue != LibUsb.SUCCESS) throw new Exception("LibUSB initialization failed: "+UsbErrorCodes.getErrCode(returningValue)); } private void getDeviceList() throws Exception{ deviceList = new DeviceList(); returningValue = LibUsb.getDeviceList(contextNS, deviceList); if (returningValue < 0) throw new Exception("Can't get device list: "+UsbErrorCodes.getErrCode(returningValue)); } private void findDevice() throws Exception{ // Searching for NS in devices: looking for NS DeviceDescriptor descriptor; for (Device device: deviceList){ descriptor = getDeviceDescriptor(device); if ((descriptor.idVendor() == VENDOR_ID) && descriptor.idProduct() == PRODUCT_ID){ deviceNS = device; break; } } if (deviceNS == null) { this.freeDeviceList(); throw new Exception("NS not found in connected USB devices"); } } private DeviceDescriptor getDeviceDescriptor(Device device) throws Exception{ DeviceDescriptor descriptor = new DeviceDescriptor(); returningValue = LibUsb.getDeviceDescriptor(device, descriptor); if (returningValue != LibUsb.SUCCESS){ this.freeDeviceList(); throw new Exception("Get USB device descriptor failure: "+UsbErrorCodes.getErrCode(returningValue)); } return descriptor; } private void openDevice() throws Exception{ // Handle NS device handlerNS = new DeviceHandle(); returningValue = LibUsb.open(deviceNS, handlerNS); if (returningValue == LibUsb.SUCCESS) return; handlerNS = null; // Avoid issue on close(); if (returningValue == LibUsb.ERROR_ACCESS) { throw new Exception(String.format( "Can't open NS USB device: %s\n" + "Double check that you have administrator privileges (you're 'root') or check 'udev' rules set for this user (linux only)!\n\n" + "Steps to set 'udev' rules:\n" + "root # vim /etc/udev/rules.d/99-NS" + ((RCM_VID == VENDOR_ID) ? "RCM" : "") + ".rules\n" + "SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", GROUP=\"plugdev\"\n" + "root # udevadm control --reload-rules && udevadm trigger\n", UsbErrorCodes.getErrCode(returningValue), VENDOR_ID, PRODUCT_ID)); } else throw new Exception("Can't open NS USB device: "+UsbErrorCodes.getErrCode(returningValue)); } private void freeDeviceList(){ LibUsb.freeDeviceList(deviceList, true); } private void setAutoDetachKernelDriver(){ // Actually, there are no drivers in Linux kernel which uses this device. returningValue = LibUsb.setAutoDetachKernelDriver(handlerNS, true); if (returningValue != LibUsb.SUCCESS) print("Skip kernel driver attach & detach ("+UsbErrorCodes.getErrCode(returningValue)+")", EMsgType.INFO); } /* private void resetDevice(){ result = LibUsb.resetDevice(handlerNS); if (returningValue != LibUsb.SUCCESS) throw new Exception("Reset device\n Returned: "+UsbErrorCodes.getErrCode(returningValue)); } */ private void setConfiguration(int configuration) throws Exception{ returningValue = LibUsb.setConfiguration(handlerNS, configuration); if (returningValue != LibUsb.SUCCESS) throw new Exception("Unable to set active configuration on device: "+UsbErrorCodes.getErrCode(returningValue)); } private void claimInterface() throws Exception{ returningValue = LibUsb.claimInterface(handlerNS, DEFAULT_INTERFACE); if (returningValue != LibUsb.SUCCESS) throw new Exception("Claim interface failure: "+UsbErrorCodes.getErrCode(returningValue)); } /** * Get USB status * @return status of connection */ public boolean isConnected() { return connected; } /** * Getter for handler * @return DeviceHandle of NS */ public DeviceHandle getNsHandler(){ return handlerNS; } /** * Getter for 'Bus ID' where NS located found */ public int getNsBus(){ return LibUsb.getBusNumber(deviceNS); } /** * Getter for 'Device address' where NS located at */ public int getNsAddress(){ return LibUsb.getDeviceAddress(deviceNS); } /** * Correct exit * */ public void close(){ // Close handler in the end if (handlerNS != null) { // Try to release interface returningValue = LibUsb.releaseInterface(handlerNS, DEFAULT_INTERFACE); if (returningValue != LibUsb.SUCCESS) { print("Release interface failure: " + UsbErrorCodes.getErrCode(returningValue) + " (sometimes it's not an issue)", EMsgType.WARNING); } LibUsb.close(handlerNS); } // Close context in the end if (contextNS != null) LibUsb.exit(contextNS); } private void print(String message, EMsgType type){ try { logPrinter.print(message, type); } catch (InterruptedException ie){ ie.printStackTrace(); } } }