• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * USB host driver for the Greybus "generic" USB module.
3  *
4  * Copyright 2014 Google Inc.
5  * Copyright 2014 Linaro Ltd.
6  *
7  * Released under the GPLv2 only.
8  *
9  */
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/usb.h>
14 #include <linux/usb/hcd.h>
15 
16 #include "greybus.h"
17 #include "gbphy.h"
18 
19 /* Greybus USB request types */
20 #define GB_USB_TYPE_HCD_START		0x02
21 #define GB_USB_TYPE_HCD_STOP		0x03
22 #define GB_USB_TYPE_HUB_CONTROL		0x04
23 
24 struct gb_usb_hub_control_request {
25 	__le16 typeReq;
26 	__le16 wValue;
27 	__le16 wIndex;
28 	__le16 wLength;
29 };
30 
31 struct gb_usb_hub_control_response {
32 	u8 buf[0];
33 };
34 
35 struct gb_usb_device {
36 	struct gb_connection *connection;
37 	struct gbphy_device *gbphy_dev;
38 };
39 
to_gb_usb_device(struct usb_hcd * hcd)40 static inline struct gb_usb_device *to_gb_usb_device(struct usb_hcd *hcd)
41 {
42 	return (struct gb_usb_device *)hcd->hcd_priv;
43 }
44 
gb_usb_device_to_hcd(struct gb_usb_device * dev)45 static inline struct usb_hcd *gb_usb_device_to_hcd(struct gb_usb_device *dev)
46 {
47 	return container_of((void *)dev, struct usb_hcd, hcd_priv);
48 }
49 
hcd_stop(struct usb_hcd * hcd)50 static void hcd_stop(struct usb_hcd *hcd)
51 {
52 	struct gb_usb_device *dev = to_gb_usb_device(hcd);
53 	int ret;
54 
55 	ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_STOP,
56 				NULL, 0, NULL, 0);
57 	if (ret)
58 		dev_err(&dev->gbphy_dev->dev, "HCD stop failed '%d'\n", ret);
59 }
60 
hcd_start(struct usb_hcd * hcd)61 static int hcd_start(struct usb_hcd *hcd)
62 {
63 	struct usb_bus *bus = hcd_to_bus(hcd);
64 	struct gb_usb_device *dev = to_gb_usb_device(hcd);
65 	int ret;
66 
67 	ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_START,
68 				NULL, 0, NULL, 0);
69 	if (ret) {
70 		dev_err(&dev->gbphy_dev->dev, "HCD start failed '%d'\n", ret);
71 		return ret;
72 	}
73 
74 	hcd->state = HC_STATE_RUNNING;
75 	if (bus->root_hub)
76 		usb_hcd_resume_root_hub(hcd);
77 	return 0;
78 }
79 
urb_enqueue(struct usb_hcd * hcd,struct urb * urb,gfp_t mem_flags)80 static int urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
81 {
82 	return -ENXIO;
83 }
84 
urb_dequeue(struct usb_hcd * hcd,struct urb * urb,int status)85 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
86 {
87 	return -ENXIO;
88 }
89 
get_frame_number(struct usb_hcd * hcd)90 static int get_frame_number(struct usb_hcd *hcd)
91 {
92 	return 0;
93 }
94 
hub_status_data(struct usb_hcd * hcd,char * buf)95 static int hub_status_data(struct usb_hcd *hcd, char *buf)
96 {
97 	return 0;
98 }
99 
hub_control(struct usb_hcd * hcd,u16 typeReq,u16 wValue,u16 wIndex,char * buf,u16 wLength)100 static int hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
101 		       char *buf, u16 wLength)
102 {
103 	struct gb_usb_device *dev = to_gb_usb_device(hcd);
104 	struct gb_operation *operation;
105 	struct gb_usb_hub_control_request *request;
106 	struct gb_usb_hub_control_response *response;
107 	size_t response_size;
108 	int ret;
109 
110 	/* FIXME: handle unspecified lengths */
111 	response_size = sizeof(*response) + wLength;
112 
113 	operation = gb_operation_create(dev->connection,
114 					GB_USB_TYPE_HUB_CONTROL,
115 					sizeof(*request),
116 					response_size,
117 					GFP_KERNEL);
118 	if (!operation)
119 		return -ENOMEM;
120 
121 	request = operation->request->payload;
122 	request->typeReq = cpu_to_le16(typeReq);
123 	request->wValue = cpu_to_le16(wValue);
124 	request->wIndex = cpu_to_le16(wIndex);
125 	request->wLength = cpu_to_le16(wLength);
126 
127 	ret = gb_operation_request_send_sync(operation);
128 	if (ret)
129 		goto out;
130 
131 	if (wLength) {
132 		/* Greybus core has verified response size */
133 		response = operation->response->payload;
134 		memcpy(buf, response->buf, wLength);
135 	}
136 out:
137 	gb_operation_put(operation);
138 
139 	return ret;
140 }
141 
142 static const struct hc_driver usb_gb_hc_driver = {
143 	.description = "greybus-hcd",
144 	.product_desc = "Greybus USB Host Controller",
145 	.hcd_priv_size = sizeof(struct gb_usb_device),
146 
147 	.flags = HCD_USB2,
148 
149 	.start = hcd_start,
150 	.stop = hcd_stop,
151 
152 	.urb_enqueue = urb_enqueue,
153 	.urb_dequeue = urb_dequeue,
154 
155 	.get_frame_number = get_frame_number,
156 	.hub_status_data = hub_status_data,
157 	.hub_control = hub_control,
158 };
159 
gb_usb_probe(struct gbphy_device * gbphy_dev,const struct gbphy_device_id * id)160 static int gb_usb_probe(struct gbphy_device *gbphy_dev,
161 			const struct gbphy_device_id *id)
162 {
163 	struct gb_connection *connection;
164 	struct device *dev = &gbphy_dev->dev;
165 	struct gb_usb_device *gb_usb_dev;
166 	struct usb_hcd *hcd;
167 	int retval;
168 
169 	hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
170 	if (!hcd)
171 		return -ENOMEM;
172 
173 	connection = gb_connection_create(gbphy_dev->bundle,
174 					  le16_to_cpu(gbphy_dev->cport_desc->id),
175 					  NULL);
176 	if (IS_ERR(connection)) {
177 		retval = PTR_ERR(connection);
178 		goto exit_usb_put;
179 	}
180 
181 	gb_usb_dev = to_gb_usb_device(hcd);
182 	gb_usb_dev->connection = connection;
183 	gb_connection_set_data(connection, gb_usb_dev);
184 	gb_usb_dev->gbphy_dev = gbphy_dev;
185 	gb_gbphy_set_data(gbphy_dev, gb_usb_dev);
186 
187 	hcd->has_tt = 1;
188 
189 	retval = gb_connection_enable(connection);
190 	if (retval)
191 		goto exit_connection_destroy;
192 
193 	/*
194 	 * FIXME: The USB bridged-PHY protocol driver depends on changes to
195 	 *        USB core which are not yet upstream.
196 	 *
197 	 *        Disable for now.
198 	 */
199 	if (1) {
200 		dev_warn(dev, "USB protocol disabled\n");
201 		retval = -EPROTONOSUPPORT;
202 		goto exit_connection_disable;
203 	}
204 
205 	retval = usb_add_hcd(hcd, 0, 0);
206 	if (retval)
207 		goto exit_connection_disable;
208 
209 	return 0;
210 
211 exit_connection_disable:
212 	gb_connection_disable(connection);
213 exit_connection_destroy:
214 	gb_connection_destroy(connection);
215 exit_usb_put:
216 	usb_put_hcd(hcd);
217 
218 	return retval;
219 }
220 
gb_usb_remove(struct gbphy_device * gbphy_dev)221 static void gb_usb_remove(struct gbphy_device *gbphy_dev)
222 {
223 	struct gb_usb_device *gb_usb_dev = gb_gbphy_get_data(gbphy_dev);
224 	struct gb_connection *connection = gb_usb_dev->connection;
225 	struct usb_hcd *hcd = gb_usb_device_to_hcd(gb_usb_dev);
226 
227 	usb_remove_hcd(hcd);
228 	gb_connection_disable(connection);
229 	gb_connection_destroy(connection);
230 	usb_put_hcd(hcd);
231 }
232 
233 static const struct gbphy_device_id gb_usb_id_table[] = {
234 	{ GBPHY_PROTOCOL(GREYBUS_PROTOCOL_USB) },
235 	{ },
236 };
237 MODULE_DEVICE_TABLE(gbphy, gb_usb_id_table);
238 
239 static struct gbphy_driver usb_driver = {
240 	.name		= "usb",
241 	.probe		= gb_usb_probe,
242 	.remove		= gb_usb_remove,
243 	.id_table	= gb_usb_id_table,
244 };
245 
246 module_gbphy_driver(usb_driver);
247 MODULE_LICENSE("GPL v2");
248