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