1ce21bfe603b3401c258c415456c915634998e133Pratyush Anand/* 2ce21bfe603b3401c258c415456c915634998e133Pratyush Anand * drivers/usb/misc/lvstest.c 3ce21bfe603b3401c258c415456c915634998e133Pratyush Anand * 4ce21bfe603b3401c258c415456c915634998e133Pratyush Anand * Test pattern generation for Link Layer Validation System Tests 5ce21bfe603b3401c258c415456c915634998e133Pratyush Anand * 6ce21bfe603b3401c258c415456c915634998e133Pratyush Anand * Copyright (C) 2014 ST Microelectronics 7ce21bfe603b3401c258c415456c915634998e133Pratyush Anand * Pratyush Anand <pratyush.anand@st.com> 8ce21bfe603b3401c258c415456c915634998e133Pratyush Anand * 9ce21bfe603b3401c258c415456c915634998e133Pratyush Anand * This file is licensed under the terms of the GNU General Public 10ce21bfe603b3401c258c415456c915634998e133Pratyush Anand * License version 2. This program is licensed "as is" without any 11ce21bfe603b3401c258c415456c915634998e133Pratyush Anand * warranty of any kind, whether express or implied. 12ce21bfe603b3401c258c415456c915634998e133Pratyush Anand */ 13ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 14ce21bfe603b3401c258c415456c915634998e133Pratyush Anand#include <linux/init.h> 15ce21bfe603b3401c258c415456c915634998e133Pratyush Anand#include <linux/kernel.h> 16ce21bfe603b3401c258c415456c915634998e133Pratyush Anand#include <linux/module.h> 17ce21bfe603b3401c258c415456c915634998e133Pratyush Anand#include <linux/platform_device.h> 18ce21bfe603b3401c258c415456c915634998e133Pratyush Anand#include <linux/slab.h> 19ce21bfe603b3401c258c415456c915634998e133Pratyush Anand#include <linux/usb.h> 20ce21bfe603b3401c258c415456c915634998e133Pratyush Anand#include <linux/usb/ch11.h> 21ce21bfe603b3401c258c415456c915634998e133Pratyush Anand#include <linux/usb/hcd.h> 22ce21bfe603b3401c258c415456c915634998e133Pratyush Anand#include <linux/usb/phy.h> 23ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 24ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstruct lvs_rh { 25ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* root hub interface */ 26ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_interface *intf; 27ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* if lvs device connected */ 28ce21bfe603b3401c258c415456c915634998e133Pratyush Anand bool present; 29ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* port no at which lvs device is present */ 30ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int portnum; 31ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* urb buffer */ 32ce21bfe603b3401c258c415456c915634998e133Pratyush Anand u8 buffer[8]; 33ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* class descriptor */ 34ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_hub_descriptor descriptor; 35ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* urb for polling interrupt pipe */ 36ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct urb *urb; 37ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* LVS RH work queue */ 38ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct workqueue_struct *rh_queue; 39ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* LVH RH work */ 40ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct work_struct rh_work; 41ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* RH port status */ 42ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_port_status port_status; 43ce21bfe603b3401c258c415456c915634998e133Pratyush Anand}; 44ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 45ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic struct usb_device *create_lvs_device(struct usb_interface *intf) 46ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 47ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *udev, *hdev; 48ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_hcd *hcd; 49ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct lvs_rh *lvs = usb_get_intfdata(intf); 50ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 51ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (!lvs->present) { 52ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(&intf->dev, "No LVS device is present\n"); 53ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return NULL; 54ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 55ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 56ce21bfe603b3401c258c415456c915634998e133Pratyush Anand hdev = interface_to_usbdev(intf); 57ce21bfe603b3401c258c415456c915634998e133Pratyush Anand hcd = bus_to_hcd(hdev->bus); 58ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 59ce21bfe603b3401c258c415456c915634998e133Pratyush Anand udev = usb_alloc_dev(hdev, hdev->bus, lvs->portnum); 60ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (!udev) { 61ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(&intf->dev, "Could not allocate lvs udev\n"); 62ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return NULL; 63ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 64ce21bfe603b3401c258c415456c915634998e133Pratyush Anand udev->speed = USB_SPEED_SUPER; 65ce21bfe603b3401c258c415456c915634998e133Pratyush Anand udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512); 66ce21bfe603b3401c258c415456c915634998e133Pratyush Anand usb_set_device_state(udev, USB_STATE_DEFAULT); 67ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 68ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (hcd->driver->enable_device) { 69ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (hcd->driver->enable_device(hcd, udev) < 0) { 70ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(&intf->dev, "Failed to enable\n"); 71ce21bfe603b3401c258c415456c915634998e133Pratyush Anand usb_put_dev(udev); 72ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return NULL; 73ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 74ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 75ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 76ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return udev; 77ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 78ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 79ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic void destroy_lvs_device(struct usb_device *udev) 80ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 81ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *hdev = udev->parent; 82ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_hcd *hcd = bus_to_hcd(hdev->bus); 83ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 84ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (hcd->driver->free_dev) 85ce21bfe603b3401c258c415456c915634998e133Pratyush Anand hcd->driver->free_dev(hcd, udev); 86ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 87ce21bfe603b3401c258c415456c915634998e133Pratyush Anand usb_put_dev(udev); 88ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 89ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 90ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic int lvs_rh_clear_port_feature(struct usb_device *hdev, 91ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int port1, int feature) 92ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 93ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), 94ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port1, 95ce21bfe603b3401c258c415456c915634998e133Pratyush Anand NULL, 0, 1000); 96ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 97ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 98ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic int lvs_rh_set_port_feature(struct usb_device *hdev, 99ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int port1, int feature) 100ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 101ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), 102ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1, 103ce21bfe603b3401c258c415456c915634998e133Pratyush Anand NULL, 0, 1000); 104ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 105ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 106ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic ssize_t u3_entry_store(struct device *dev, 107ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct device_attribute *attr, const char *buf, size_t count) 108ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 109ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_interface *intf = to_usb_interface(dev); 110ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *hdev = interface_to_usbdev(intf); 111ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct lvs_rh *lvs = usb_get_intfdata(intf); 112ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *udev; 113ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int ret; 114ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 115ce21bfe603b3401c258c415456c915634998e133Pratyush Anand udev = create_lvs_device(intf); 116ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (!udev) { 117ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "failed to create lvs device\n"); 118ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return -ENOMEM; 119ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 120ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 121ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = lvs_rh_set_port_feature(hdev, lvs->portnum, 122ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_FEAT_SUSPEND); 123ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) 124ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "can't issue U3 entry %d\n", ret); 125ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 126ce21bfe603b3401c258c415456c915634998e133Pratyush Anand destroy_lvs_device(udev); 127ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 128ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) 129ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 130ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 131ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return count; 132ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 133ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic DEVICE_ATTR_WO(u3_entry); 134ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 135ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic ssize_t u3_exit_store(struct device *dev, 136ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct device_attribute *attr, const char *buf, size_t count) 137ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 138ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_interface *intf = to_usb_interface(dev); 139ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *hdev = interface_to_usbdev(intf); 140ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct lvs_rh *lvs = usb_get_intfdata(intf); 141ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *udev; 142ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int ret; 143ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 144ce21bfe603b3401c258c415456c915634998e133Pratyush Anand udev = create_lvs_device(intf); 145ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (!udev) { 146ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "failed to create lvs device\n"); 147ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return -ENOMEM; 148ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 149ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 150ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = lvs_rh_clear_port_feature(hdev, lvs->portnum, 151ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_FEAT_SUSPEND); 152ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) 153ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "can't issue U3 exit %d\n", ret); 154ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 155ce21bfe603b3401c258c415456c915634998e133Pratyush Anand destroy_lvs_device(udev); 156ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 157ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) 158ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 159ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 160ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return count; 161ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 162ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic DEVICE_ATTR_WO(u3_exit); 163ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 164ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic ssize_t hot_reset_store(struct device *dev, 165ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct device_attribute *attr, const char *buf, size_t count) 166ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 167ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_interface *intf = to_usb_interface(dev); 168ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *hdev = interface_to_usbdev(intf); 169ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct lvs_rh *lvs = usb_get_intfdata(intf); 170ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int ret; 171ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 172ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = lvs_rh_set_port_feature(hdev, lvs->portnum, 173ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_FEAT_RESET); 174ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) { 175ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "can't issue hot reset %d\n", ret); 176ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 177ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 178ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 179ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return count; 180ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 181ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic DEVICE_ATTR_WO(hot_reset); 182ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 183ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic ssize_t u2_timeout_store(struct device *dev, 184ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct device_attribute *attr, const char *buf, size_t count) 185ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 186ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_interface *intf = to_usb_interface(dev); 187ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *hdev = interface_to_usbdev(intf); 188ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct lvs_rh *lvs = usb_get_intfdata(intf); 189ce21bfe603b3401c258c415456c915634998e133Pratyush Anand unsigned long val; 190ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int ret; 191ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 192ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = kstrtoul(buf, 10, &val); 193ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) { 194ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "couldn't parse string %d\n", ret); 195ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 196ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 197ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 198ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (val < 0 || val > 127) 199ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return -EINVAL; 200ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 201ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = lvs_rh_set_port_feature(hdev, lvs->portnum | (val << 8), 202ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_FEAT_U2_TIMEOUT); 203ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) { 204ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "Error %d while setting U2 timeout %ld\n", ret, val); 205ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 206ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 207ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 208ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return count; 209ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 210ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic DEVICE_ATTR_WO(u2_timeout); 211ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 212ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic ssize_t u1_timeout_store(struct device *dev, 213ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct device_attribute *attr, const char *buf, size_t count) 214ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 215ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_interface *intf = to_usb_interface(dev); 216ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *hdev = interface_to_usbdev(intf); 217ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct lvs_rh *lvs = usb_get_intfdata(intf); 218ce21bfe603b3401c258c415456c915634998e133Pratyush Anand unsigned long val; 219ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int ret; 220ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 221ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = kstrtoul(buf, 10, &val); 222ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) { 223ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "couldn't parse string %d\n", ret); 224ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 225ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 226ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 227ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (val < 0 || val > 127) 228ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return -EINVAL; 229ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 230ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = lvs_rh_set_port_feature(hdev, lvs->portnum | (val << 8), 231ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_FEAT_U1_TIMEOUT); 232ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) { 233ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "Error %d while setting U1 timeout %ld\n", ret, val); 234ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 235ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 236ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 237ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return count; 238ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 239ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic DEVICE_ATTR_WO(u1_timeout); 240ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 241ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic ssize_t get_dev_desc_store(struct device *dev, 242ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct device_attribute *attr, const char *buf, size_t count) 243ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 244ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_interface *intf = to_usb_interface(dev); 245ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *udev; 246ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device_descriptor *descriptor; 247ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int ret; 248ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 249ce21bfe603b3401c258c415456c915634998e133Pratyush Anand descriptor = kmalloc(sizeof(*descriptor), GFP_KERNEL); 250ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (!descriptor) { 251ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "failed to allocate descriptor memory\n"); 252ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return -ENOMEM; 253ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 254ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 255ce21bfe603b3401c258c415456c915634998e133Pratyush Anand udev = create_lvs_device(intf); 256ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (!udev) { 257ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "failed to create lvs device\n"); 258ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = -ENOMEM; 259ce21bfe603b3401c258c415456c915634998e133Pratyush Anand goto free_desc; 260ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 261ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 262ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = usb_control_msg(udev, (PIPE_CONTROL << 30) | USB_DIR_IN, 263ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, USB_DT_DEVICE << 8, 264ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 0, descriptor, sizeof(*descriptor), 265ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_CTRL_GET_TIMEOUT); 266ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) 267ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(dev, "can't read device descriptor %d\n", ret); 268ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 269ce21bfe603b3401c258c415456c915634998e133Pratyush Anand destroy_lvs_device(udev); 270ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 271ce21bfe603b3401c258c415456c915634998e133Pratyush Anandfree_desc: 272ce21bfe603b3401c258c415456c915634998e133Pratyush Anand kfree(descriptor); 273ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 274ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) 275ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 276ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 277ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return count; 278ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 279ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic DEVICE_ATTR_WO(get_dev_desc); 280ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 281ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic struct attribute *lvs_attributes[] = { 282ce21bfe603b3401c258c415456c915634998e133Pratyush Anand &dev_attr_get_dev_desc.attr, 283ce21bfe603b3401c258c415456c915634998e133Pratyush Anand &dev_attr_u1_timeout.attr, 284ce21bfe603b3401c258c415456c915634998e133Pratyush Anand &dev_attr_u2_timeout.attr, 285ce21bfe603b3401c258c415456c915634998e133Pratyush Anand &dev_attr_hot_reset.attr, 286ce21bfe603b3401c258c415456c915634998e133Pratyush Anand &dev_attr_u3_entry.attr, 287ce21bfe603b3401c258c415456c915634998e133Pratyush Anand &dev_attr_u3_exit.attr, 288ce21bfe603b3401c258c415456c915634998e133Pratyush Anand NULL 289ce21bfe603b3401c258c415456c915634998e133Pratyush Anand}; 290ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 291ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic const struct attribute_group lvs_attr_group = { 292ce21bfe603b3401c258c415456c915634998e133Pratyush Anand .attrs = lvs_attributes, 293ce21bfe603b3401c258c415456c915634998e133Pratyush Anand}; 294ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 295ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic void lvs_rh_work(struct work_struct *work) 296ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 297ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct lvs_rh *lvs = container_of(work, struct lvs_rh, rh_work); 298ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_interface *intf = lvs->intf; 299ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *hdev = interface_to_usbdev(intf); 300ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_hcd *hcd = bus_to_hcd(hdev->bus); 301ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_hub_descriptor *descriptor = &lvs->descriptor; 302ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_port_status *port_status = &lvs->port_status; 303ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int i, ret = 0; 304ce21bfe603b3401c258c415456c915634998e133Pratyush Anand u16 portchange; 305ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 306ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* Examine each root port */ 307ce21bfe603b3401c258c415456c915634998e133Pratyush Anand for (i = 1; i <= descriptor->bNbrPorts; i++) { 308ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), 309ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, i, 310ce21bfe603b3401c258c415456c915634998e133Pratyush Anand port_status, sizeof(*port_status), 1000); 311ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 4) 312ce21bfe603b3401c258c415456c915634998e133Pratyush Anand continue; 313ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 314b1bd3f1a398ef27dd09a594c38dde34472b453afPratyush Anand portchange = le16_to_cpu(port_status->wPortChange); 315ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 316ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (portchange & USB_PORT_STAT_C_LINK_STATE) 317ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs_rh_clear_port_feature(hdev, i, 318ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_FEAT_C_PORT_LINK_STATE); 319ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (portchange & USB_PORT_STAT_C_ENABLE) 320ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs_rh_clear_port_feature(hdev, i, 321ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_FEAT_C_ENABLE); 322ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (portchange & USB_PORT_STAT_C_RESET) 323ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs_rh_clear_port_feature(hdev, i, 324ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_FEAT_C_RESET); 325ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (portchange & USB_PORT_STAT_C_BH_RESET) 326ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs_rh_clear_port_feature(hdev, i, 327ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_FEAT_C_BH_PORT_RESET); 328ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (portchange & USB_PORT_STAT_C_CONNECTION) { 329ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs_rh_clear_port_feature(hdev, i, 330ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_FEAT_C_CONNECTION); 331ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 332b1bd3f1a398ef27dd09a594c38dde34472b453afPratyush Anand if (le16_to_cpu(port_status->wPortStatus) & 333ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_PORT_STAT_CONNECTION) { 334ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs->present = true; 335ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs->portnum = i; 3363d46e73dfdb840f460e5b06416965d132570ec33Antoine Tenart if (hcd->usb_phy) 3373d46e73dfdb840f460e5b06416965d132570ec33Antoine Tenart usb_phy_notify_connect(hcd->usb_phy, 338ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_SPEED_SUPER); 339ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } else { 340ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs->present = false; 3413d46e73dfdb840f460e5b06416965d132570ec33Antoine Tenart if (hcd->usb_phy) 3423d46e73dfdb840f460e5b06416965d132570ec33Antoine Tenart usb_phy_notify_disconnect(hcd->usb_phy, 343ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_SPEED_SUPER); 344ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 345ce21bfe603b3401c258c415456c915634998e133Pratyush Anand break; 346ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 347ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 348ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 349ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = usb_submit_urb(lvs->urb, GFP_KERNEL); 350ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret != 0 && ret != -ENODEV && ret != -EPERM) 351ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(&intf->dev, "urb resubmit error %d\n", ret); 352ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 353ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 354ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic void lvs_rh_irq(struct urb *urb) 355ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 356ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct lvs_rh *lvs = urb->context; 357ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 358ce21bfe603b3401c258c415456c915634998e133Pratyush Anand queue_work(lvs->rh_queue, &lvs->rh_work); 359ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 360ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 361ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic int lvs_rh_probe(struct usb_interface *intf, 362ce21bfe603b3401c258c415456c915634998e133Pratyush Anand const struct usb_device_id *id) 363ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 364ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_device *hdev; 365ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_host_interface *desc; 366ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct usb_endpoint_descriptor *endpoint; 367ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct lvs_rh *lvs; 368ce21bfe603b3401c258c415456c915634998e133Pratyush Anand unsigned int pipe; 369ce21bfe603b3401c258c415456c915634998e133Pratyush Anand int ret, maxp; 370ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 371ce21bfe603b3401c258c415456c915634998e133Pratyush Anand hdev = interface_to_usbdev(intf); 372ce21bfe603b3401c258c415456c915634998e133Pratyush Anand desc = intf->cur_altsetting; 373ce21bfe603b3401c258c415456c915634998e133Pratyush Anand endpoint = &desc->endpoint[0].desc; 374ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 375ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* valid only for SS root hub */ 376ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (hdev->descriptor.bDeviceProtocol != USB_HUB_PR_SS || hdev->parent) { 377ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(&intf->dev, "Bind LVS driver with SS root Hub only\n"); 378ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return -EINVAL; 379ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 380ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 381ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs = devm_kzalloc(&intf->dev, sizeof(*lvs), GFP_KERNEL); 382ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (!lvs) 383ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return -ENOMEM; 384ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 385ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs->intf = intf; 386ce21bfe603b3401c258c415456c915634998e133Pratyush Anand usb_set_intfdata(intf, lvs); 387ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 388ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* how many number of ports this root hub has */ 389ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0), 390ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, 391ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_DT_SS_HUB << 8, 0, &lvs->descriptor, 392ce21bfe603b3401c258c415456c915634998e133Pratyush Anand USB_DT_SS_HUB_SIZE, USB_CTRL_GET_TIMEOUT); 393ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < (USB_DT_HUB_NONVAR_SIZE + 2)) { 394ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(&hdev->dev, "wrong root hub descriptor read %d\n", ret); 395ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 396ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 397ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 398ce21bfe603b3401c258c415456c915634998e133Pratyush Anand /* submit urb to poll interrupt endpoint */ 399ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs->urb = usb_alloc_urb(0, GFP_KERNEL); 400ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (!lvs->urb) { 401ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(&intf->dev, "couldn't allocate lvs urb\n"); 402ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return -ENOMEM; 403ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 404ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 405ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs->rh_queue = create_singlethread_workqueue("lvs_rh_queue"); 406ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (!lvs->rh_queue) { 407ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(&intf->dev, "couldn't create workqueue\n"); 408ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = -ENOMEM; 409ce21bfe603b3401c258c415456c915634998e133Pratyush Anand goto free_urb; 410ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 411ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 412ce21bfe603b3401c258c415456c915634998e133Pratyush Anand INIT_WORK(&lvs->rh_work, lvs_rh_work); 413ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 414ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = sysfs_create_group(&intf->dev.kobj, &lvs_attr_group); 415ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) { 416ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(&intf->dev, "Failed to create sysfs node %d\n", ret); 417ce21bfe603b3401c258c415456c915634998e133Pratyush Anand goto destroy_queue; 418ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 419ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 420ce21bfe603b3401c258c415456c915634998e133Pratyush Anand pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress); 421ce21bfe603b3401c258c415456c915634998e133Pratyush Anand maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe)); 422ce21bfe603b3401c258c415456c915634998e133Pratyush Anand usb_fill_int_urb(lvs->urb, hdev, pipe, &lvs->buffer[0], maxp, 423ce21bfe603b3401c258c415456c915634998e133Pratyush Anand lvs_rh_irq, lvs, endpoint->bInterval); 424ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 425ce21bfe603b3401c258c415456c915634998e133Pratyush Anand ret = usb_submit_urb(lvs->urb, GFP_KERNEL); 426ce21bfe603b3401c258c415456c915634998e133Pratyush Anand if (ret < 0) { 427ce21bfe603b3401c258c415456c915634998e133Pratyush Anand dev_err(&intf->dev, "couldn't submit lvs urb %d\n", ret); 428ce21bfe603b3401c258c415456c915634998e133Pratyush Anand goto sysfs_remove; 429ce21bfe603b3401c258c415456c915634998e133Pratyush Anand } 430ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 431ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 432ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 433ce21bfe603b3401c258c415456c915634998e133Pratyush Anandsysfs_remove: 434ce21bfe603b3401c258c415456c915634998e133Pratyush Anand sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group); 435ce21bfe603b3401c258c415456c915634998e133Pratyush Ananddestroy_queue: 436ce21bfe603b3401c258c415456c915634998e133Pratyush Anand destroy_workqueue(lvs->rh_queue); 437ce21bfe603b3401c258c415456c915634998e133Pratyush Anandfree_urb: 438ce21bfe603b3401c258c415456c915634998e133Pratyush Anand usb_free_urb(lvs->urb); 439ce21bfe603b3401c258c415456c915634998e133Pratyush Anand return ret; 440ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 441ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 442ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic void lvs_rh_disconnect(struct usb_interface *intf) 443ce21bfe603b3401c258c415456c915634998e133Pratyush Anand{ 444ce21bfe603b3401c258c415456c915634998e133Pratyush Anand struct lvs_rh *lvs = usb_get_intfdata(intf); 445ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 446ce21bfe603b3401c258c415456c915634998e133Pratyush Anand sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group); 447ce21bfe603b3401c258c415456c915634998e133Pratyush Anand destroy_workqueue(lvs->rh_queue); 448ce21bfe603b3401c258c415456c915634998e133Pratyush Anand usb_free_urb(lvs->urb); 449ce21bfe603b3401c258c415456c915634998e133Pratyush Anand} 450ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 451ce21bfe603b3401c258c415456c915634998e133Pratyush Anandstatic struct usb_driver lvs_driver = { 452ce21bfe603b3401c258c415456c915634998e133Pratyush Anand .name = "lvs", 453ce21bfe603b3401c258c415456c915634998e133Pratyush Anand .probe = lvs_rh_probe, 454ce21bfe603b3401c258c415456c915634998e133Pratyush Anand .disconnect = lvs_rh_disconnect, 455ce21bfe603b3401c258c415456c915634998e133Pratyush Anand}; 456ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 457ce21bfe603b3401c258c415456c915634998e133Pratyush Anandmodule_usb_driver(lvs_driver); 458ce21bfe603b3401c258c415456c915634998e133Pratyush Anand 459ce21bfe603b3401c258c415456c915634998e133Pratyush AnandMODULE_DESCRIPTION("Link Layer Validation System Driver"); 460ce21bfe603b3401c258c415456c915634998e133Pratyush AnandMODULE_LICENSE("GPL"); 461