1e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney/* 2e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 3e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * 2005-2007 Takahiro Hirofuchi 4e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * 5e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * This program is free software: you can redistribute it and/or modify 6e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * it under the terms of the GNU General Public License as published by 7e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * the Free Software Foundation, either version 2 of the License, or 8e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * (at your option) any later version. 9e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * 10e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * This program is distributed in the hope that it will be useful, 11e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * but WITHOUT ANY WARRANTY; without even the implied warranty of 12e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * GNU General Public License for more details. 14e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * 15e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * You should have received a copy of the GNU General Public License 16e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney * along with this program. If not, see <http://www.gnu.org/licenses/>. 17e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney */ 18e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 199cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney#include <sysfs/libsysfs.h> 209cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 219cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney#include <errno.h> 22e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney#include <stdio.h> 239cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney#include <string.h> 24e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 25e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney#include <getopt.h> 26e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 27e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney#include "usbip_common.h" 28e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney#include "utils.h" 29e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney#include "usbip.h" 30e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 31e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooneystatic const char usbip_unbind_usage_string[] = 32e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney "usbip unbind <args>\n" 33e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney " -b, --busid=<busid> Unbind " USBIP_HOST_DRV_NAME ".ko from " 34e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney "device on <busid>\n"; 35e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 36e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooneyvoid usbip_unbind_usage(void) 37e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney{ 38e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney printf("usage: %s", usbip_unbind_usage_string); 39e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney} 40e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 419cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooneystatic int unbind_device(char *busid) 42e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney{ 439cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney char bus_type[] = "usb"; 449cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney struct sysfs_driver *usbip_host_drv; 459cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney struct sysfs_device *dev; 469cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney struct dlist *devlist; 479cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney int verified = 0; 489cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney int rc, ret = -1; 499cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 509cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney char attr_name[] = "bConfigurationValue"; 519cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney char sysfs_mntpath[SYSFS_PATH_MAX]; 529cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney char busid_attr_path[SYSFS_PATH_MAX]; 539cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney struct sysfs_attribute *busid_attr; 549cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney char *val = NULL; 559cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney int len; 569cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 579cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney /* verify the busid device is using usbip-host */ 589cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney usbip_host_drv = sysfs_open_driver(bus_type, USBIP_HOST_DRV_NAME); 599cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney if (!usbip_host_drv) { 609cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney err("could not open %s driver: %s", USBIP_HOST_DRV_NAME, 619cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney strerror(errno)); 629cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney return -1; 639cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney } 649cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 659cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney devlist = sysfs_get_driver_devices(usbip_host_drv); 669cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney if (!devlist) { 679cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney err("%s is not in use by any devices", USBIP_HOST_DRV_NAME); 689cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney goto err_close_usbip_host_drv; 699cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney } 709cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 719cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney dlist_for_each_data(devlist, dev, struct sysfs_device) { 729cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney if (!strncmp(busid, dev->name, strlen(busid)) && 739cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney !strncmp(dev->driver_name, USBIP_HOST_DRV_NAME, 749cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney strlen(USBIP_HOST_DRV_NAME))) { 759cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney verified = 1; 769cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney break; 779cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney } 789cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney } 799cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 809cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney if (!verified) { 819cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney err("device on busid %s is not using %s", busid, 829cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney USBIP_HOST_DRV_NAME); 839cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney goto err_close_usbip_host_drv; 849cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney } 859cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 869cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney /* 879cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney * NOTE: A read and write of an attribute value of the device busid 889cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney * refers to must be done to start probing. That way a rebind of the 899cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney * default driver for the device occurs. 909cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney * 919cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney * This seems very hackish and adds a lot of pointless code. I think it 929cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney * should be done in the kernel by the driver after del_match_busid is 939cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney * finished! 949cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney */ 959cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 969cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); 979cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney if (rc < 0) { 989cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney err("sysfs must be mounted: %s", strerror(errno)); 999cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney return -1; 1009cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney } 101e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 1029cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney snprintf(busid_attr_path, sizeof(busid_attr_path), "%s/%s/%s/%s/%s/%s", 1039cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DEVICES_NAME, 1049cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney busid, attr_name); 1059cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 1069cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney /* read a device attribute */ 1079cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney busid_attr = sysfs_open_attribute(busid_attr_path); 1089cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney if (!busid_attr) { 1099cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney err("could not open %s/%s: %s", busid, attr_name, 1109cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney strerror(errno)); 111e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney return -1; 112e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney } 113e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 1149cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney if (sysfs_read_attribute(busid_attr) < 0) { 1159cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney err("problem reading attribute: %s", strerror(errno)); 1169cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney goto err_out; 1179cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney } 1189cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 1199cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney len = busid_attr->len; 1209cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney val = malloc(len); 1219cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney *val = *busid_attr->value; 1229cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney sysfs_close_attribute(busid_attr); 1239cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 1249cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney /* notify driver of unbind */ 125e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney rc = modify_match_busid(busid, 0); 126e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney if (rc < 0) { 1279cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney err("unable to unbind device on %s", busid); 1289cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney goto err_out; 1299cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney } 1309cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 1319cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney /* write the device attribute */ 1329cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney busid_attr = sysfs_open_attribute(busid_attr_path); 1339cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney if (!busid_attr) { 1349cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney err("could not open %s/%s: %s", busid, attr_name, 1359cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney strerror(errno)); 136e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney return -1; 137e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney } 138e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 1399cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney rc = sysfs_write_attribute(busid_attr, val, len); 140e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney if (rc < 0) { 1419cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney err("problem writing attribute: %s", strerror(errno)); 1429cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney goto err_out; 143e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney } 1449cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney sysfs_close_attribute(busid_attr); 1459cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 1469cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney ret = 0; 1479cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney printf("unbind device on busid %s: complete\n", busid); 148e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 1499cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooneyerr_out: 1509cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney free(val); 1519cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooneyerr_close_usbip_host_drv: 1529cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney sysfs_close_driver(usbip_host_drv); 153e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 1549cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney return ret; 155e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney} 156e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 157e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooneyint usbip_unbind(int argc, char *argv[]) 158e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney{ 159e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney static const struct option opts[] = { 160e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney { "busid", required_argument, NULL, 'b' }, 1619cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney { NULL, 0, NULL, 0 } 162e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney }; 1639cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney 164e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney int opt; 165e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney int ret = -1; 166e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 167e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney for (;;) { 168e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney opt = getopt_long(argc, argv, "b:", opts, NULL); 169e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 170e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney if (opt == -1) 171e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney break; 172e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 173e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney switch (opt) { 174e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney case 'b': 1759cda5704115d1611b408d8bd0e6e9dfd8a3617cbmatt mooney ret = unbind_device(optarg); 176e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney goto out; 177e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney default: 178e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney goto err_out; 179e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney } 180e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney } 181e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney 182e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooneyerr_out: 183e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney usbip_unbind_usage(); 184e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooneyout: 185e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney return ret; 186e9837bbb3e694eef4c55c934ebf1f8a0399b142cmatt mooney} 187