static ssize_t wusb_disconnect_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct usb_device *usb_dev; struct wusbhc *wusbhc; unsigned command; u8 port_idx; if (sscanf(buf, "%u", &command) != 1) return -EINVAL; if (command == 0) return size; usb_dev = to_usb_device(dev); wusbhc = wusbhc_get_by_usb_dev(usb_dev); if (wusbhc == NULL) return -ENODEV; mutex_lock(&wusbhc->mutex); port_idx = wusb_port_no_to_idx(usb_dev->portnum); __wusbhc_dev_disable(wusbhc, port_idx); mutex_unlock(&wusbhc->mutex); wusbhc_put(wusbhc); return size; }
/* * Clear a port feature... * * @wusbhc is assumed referenced and @wusbhc->mutex unlocked. */ static int wusbhc_rh_clear_port_feat(struct wusbhc *wusbhc, u16 feature, u8 selector, u8 port_idx) { int result = 0; struct device *dev = wusbhc->dev; if (port_idx > wusbhc->ports_max) return -EINVAL; mutex_lock(&wusbhc->mutex); switch (feature) { case USB_PORT_FEAT_POWER: /* fake port always on */ /* According to USB2.0[11.24.2.7.1.4], no need to implement? */ case USB_PORT_FEAT_C_OVER_CURRENT: break; case USB_PORT_FEAT_C_RESET: wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_RESET; break; case USB_PORT_FEAT_C_CONNECTION: wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_CONNECTION; break; case USB_PORT_FEAT_ENABLE: __wusbhc_dev_disable(wusbhc, port_idx); break; case USB_PORT_FEAT_C_ENABLE: wusb_port_by_idx(wusbhc, port_idx)->change &= ~USB_PORT_STAT_C_ENABLE; break; case USB_PORT_FEAT_SUSPEND: case USB_PORT_FEAT_C_SUSPEND: dev_err(dev, "(port_idx %d) Clear feat %d/%d UNIMPLEMENTED\n", port_idx, feature, selector); result = -ENOSYS; break; default: dev_err(dev, "(port_idx %d) Clear feat %d/%d UNKNOWN\n", port_idx, feature, selector); result = -EPIPE; break; } mutex_unlock(&wusbhc->mutex); return result; }