在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。