How to programatically unplug & replug an USB device in linux?

本文介绍在 Linux 系统中如何通过两种方法实现 USB 设备的热插拔:一是利用 usbfs 系统调用 reset USB 设备;二是修改设备驱动程序,增加 USBDEVFS_RESET 选项。

在linux,更新了usb设备的firmware后,你需要重新插拔一下usb设备来让系统读取到新的usb设备信息。

我们可以通过软件的方式让usb设备reset,实现hot-replug目的,让系统重新读取usb设备信息。

 

有两种方法让内核replug USB设备:

一:使用usbfs系统reset USB设备

先看看源码:

在drivers/usb/core/devio.c里的usbdev_ioctl函数里有

	case USBDEVFS_RESET:
		snoop(&dev->dev, "%s: RESET\n", __func__);
		ret = proc_resetdevice(ps);
		break;

 

proc_resetdevice调用了drivers/usb/core/hub.c的usb_reset_device重置usb设备,使内核replug该usb

 

只需打开usbfs里面对应的usb文件进行ioctl(fd, USBDEVFS_RESET, NULL)即可。

 

二:修改设备驱动,在ioctl里添加USBDEVFS_RESET选项

我在ftdi_sio驱动里,添加

static int ftdi_device_reset(struct usb_serial_port *port)
{
	struct usb_device *dev = port->serial->dev;
	int ret;

	ret = usb_lock_device_for_reset(dev,NULL);
	if (ret == 0) {
		ret = usb_reset_device(dev);
		usb_unlock_device(dev);
	}
	return ret;
}

static int ftdi_ioctl(struct tty_struct *tty, struct file *file,
					unsigned int cmd, unsigned long arg)
{
	struct usb_serial_port *port = tty->driver_data;
	struct ftdi_private *priv = usb_get_serial_port_data(port);

	dbg("%s cmd 0x%04x", __func__, cmd);

	/* Based on code from acm.c and others */
	switch (cmd) {

	/* To support usb_control_msg to ttyUSB */
	case USBDEVFS_CONTROL:
		//dev_printk(KERN_DEBUG, &port->serial->dev->dev, "%s: CONTROL\n", __FUNCTION__);
		return tty_usb_control(port, (void __user *)arg);
		break;

	/* reset after downloading new firmware */
	case USBDEVFS_RESET:
		return ftdi_device_reset(port);
		break;

 

使用该内核,则可以通过设备驱动进行replug该usb设备,很方便。

使用驱动reset设备:

static int usb_device_reset(int fd)
{
  int ret;
	
  #define FTDI_USBDEV_RESET	_IO('U', 20)
  ret = ioctl(fd, FTDI_USBDEV_RESET, NULL);
  if (ret < 0)
    printf("USB device reset: %s\n", strerror(errno));

  return ret;
}

上面的#define FTDI_USBDEV_RESET  _IO('U', 20),其实就是USBDEVFS_RESET

 

我使用修改了的驱动实现,实际效果如下:

root@DLRC:/opt/sniffer/bin#setmoteid_4x -d /dev/ttyUSB0 -w 92
product :HKUST ATC Telos Rev B(9), len:24
old product :HKUST ATC Telos Rev B(9), len:24
new product :   HKUST ATC Telos Rev B(92)
serial save:DS000338, len:8
ftdi_sio 1-1.4.3:1.0: forced unbind
ep93xx-ohci ep93xx-ohci: shutdown urb c563dde0 ep1in-bulk
ftdi_sio 1-1.4.3:1.0: device disconnected
hub 1-1.4:1.0: state 7 ports 4 chg 0000 evt 0008
hub 1-1.4:1.0: state 7 ports 4 chg 0000 evt 0008
usb 1-1.4.3: reset full speed USB device using ep93xx-ohci and address 4
hub 1-1.4:1.0: state 7 ports 4 chg 0000 evt 0008
hub 1-1.4:1.0: state 7 ports 4 chg 0000 evt 0008
usb 1-1.4.3: ep0 maxpacket = 8
usbserial_generic 1-1.4.3:1.0: usb_probe_interface
usbserial_generic 1-1.4.3:1.0: usb_probe_interface - got id
ftdi_sio 1-1.4.3:1.0: usb_probe_interface
ftdi_sio 1-1.4.3:1.0: usb_probe_interface - got id
ftdi_sio 1-1.4.3:1.0: FTDI USB Serial Device converter detected
usb 1-1.4.3: Detected FT232BM
usb 1-1.4.3: FTDI USB Serial Device converter now attached to ttyUSB1
ftdi_sio ttyUSB0: FTDI USB Serial Device converter now disconnected from ttyUSB0


可以看到,reset它,内核就replug该USB。

 


 

 

导出手机log有多种方法: - **导出手机中的`traces.txt`文件**:可使用`adb pull /data/anr/traces.txt f:/log.txt`命令,将手机上的`traces.txt`导出到电脑的F盘下,文件名是`log.txt`。如果该命令失效,可采用曲线导出方式,依次执行以下操作: 1. 输入`adb shell`; 2. 输入`cat /data/anr/traces.txt &gt;/mnt/sdcard/log/zz.txt`,将`traces.txt`内容文件转移到设备中的`mnt/sdcard/log/zz.txt`文件中; 3. 输入`exit` [^1]。 - **导出LogCat存储的log**: - 通过命令导出:使用`adb logcat -d &gt; D:\logcat.txt`命令,详细参考&lt;http://developer.android.com/tools/help/adb.html#logcat&gt; [^2]。 - 在程序中获取Log:首先在AndroidManifest.xml文件中添加权限`&lt;uses-permission android:name=&quot;android.permission.READ_LOGS&quot; /&gt;`,然后在Java代码中可以使用如下代码获取Log: ```java public class LogTest extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); try { Process process = Runtime.getRuntime().exec(&quot;logcat -d&quot;); BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(process.getInputStream())); StringBuilder log = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { log.append(line); } TextView tv = (TextView) findViewById(R.id.textView1); tv.setText(log.toString()); } catch (IOException e) { } } } ``` 详细参考&lt;http://www.helloandroid.com/tutorials/reading-logs-programatically&gt; [^2]。 - **Google Pixel手机抓取hci log**:如果文件在`/data/misc/bluetooth/logs/`,需要root权限,可使用`adb root`和`adb pull /data/misc/bluetooth/logs/btsnoop_hci.log`命令 [^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值