2 * USB host driver for the Greybus "generic" USB module.
4 * Copyright 2014 Google Inc.
5 * Copyright 2014 Linaro Ltd.
7 * Released under the GPLv2 only.
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>
18 /* Version of the Greybus USB protocol we support */
19 #define GB_USB_VERSION_MAJOR 0x00
20 #define GB_USB_VERSION_MINOR 0x01
22 /* Greybus USB request types */
23 #define GB_USB_TYPE_INVALID 0x00
24 #define GB_USB_TYPE_PROTOCOL_VERSION 0x01
25 #define GB_USB_TYPE_HCD_START 0x02
26 #define GB_USB_TYPE_HCD_STOP 0x03
27 #define GB_USB_TYPE_HUB_CONTROL 0x04
29 struct gb_usb_hub_control_request {
36 struct gb_usb_hub_control_response {
40 struct gb_usb_device {
41 struct gb_connection *connection;
47 static inline struct gb_usb_device *to_gb_usb_device(struct usb_hcd *hcd)
49 return (struct gb_usb_device *)hcd->hcd_priv;
52 static inline struct usb_hcd *gb_usb_device_to_hcd(struct gb_usb_device *dev)
54 return container_of((void *)dev, struct usb_hcd, hcd_priv);
57 /* Define get_version() routine */
58 define_get_version(gb_usb_device, USB);
60 static void hcd_stop(struct usb_hcd *hcd)
62 struct gb_usb_device *dev = to_gb_usb_device(hcd);
65 ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_STOP,
68 dev_err(&dev->connection->dev, "HCD stop failed '%d'\n", ret);
71 static int hcd_start(struct usb_hcd *hcd)
73 struct usb_bus *bus = hcd_to_bus(hcd);
74 struct gb_usb_device *dev = to_gb_usb_device(hcd);
77 ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_START,
80 dev_err(&dev->connection->dev, "HCD start failed '%d'\n", ret);
84 hcd->state = HC_STATE_RUNNING;
86 usb_hcd_resume_root_hub(hcd);
90 static int urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
95 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
100 static int get_frame_number(struct usb_hcd *hcd)
105 static int hub_status_data(struct usb_hcd *hcd, char *buf)
110 static int hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
111 char *buf, u16 wLength)
113 struct gb_usb_device *dev = to_gb_usb_device(hcd);
114 struct gb_operation *operation;
115 struct gb_usb_hub_control_request *request;
116 struct gb_usb_hub_control_response *response;
117 size_t response_size;
120 /* FIXME: handle unspecified lengths */
121 response_size = sizeof(*response) + wLength;
123 operation = gb_operation_create(dev->connection,
124 GB_USB_TYPE_HUB_CONTROL,
131 request = operation->request->payload;
132 request->typeReq = cpu_to_le16(typeReq);
133 request->wValue = cpu_to_le16(wValue);
134 request->wIndex = cpu_to_le16(wIndex);
135 request->wLength = cpu_to_le16(wLength);
137 ret = gb_operation_request_send_sync(operation);
142 /* Greybus core has verified response size */
143 response = operation->response->payload;
144 memcpy(buf, response->buf, wLength);
147 gb_operation_put(operation);
152 static struct hc_driver usb_gb_hc_driver = {
153 .description = "greybus-hcd",
154 .product_desc = "Greybus USB Host Controller",
155 .hcd_priv_size = sizeof(struct gb_usb_device),
162 .urb_enqueue = urb_enqueue,
163 .urb_dequeue = urb_dequeue,
165 .get_frame_number = get_frame_number,
166 .hub_status_data = hub_status_data,
167 .hub_control = hub_control,
170 static int gb_usb_connection_init(struct gb_connection *connection)
172 struct device *dev = &connection->dev;
173 struct gb_usb_device *gb_usb_dev;
178 hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
182 gb_usb_dev = to_gb_usb_device(hcd);
183 gb_usb_dev->connection = connection;
184 connection->private = gb_usb_dev;
186 /* Check for compatible protocol version */
187 retval = get_version(gb_usb_dev);
193 retval = usb_add_hcd(hcd, 0, 0);
205 static void gb_usb_connection_exit(struct gb_connection *connection)
207 struct gb_usb_device *gb_usb_dev = connection->private;
208 struct usb_hcd *hcd = gb_usb_device_to_hcd(gb_usb_dev);
214 static struct gb_protocol usb_protocol = {
216 .id = GREYBUS_PROTOCOL_USB,
219 .connection_init = gb_usb_connection_init,
220 .connection_exit = gb_usb_connection_exit,
221 .request_recv = NULL, /* FIXME we have requests!!! */
224 gb_builtin_protocol_driver(usb_protocol);