0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/slab.h>
0011 #include <linux/usb.h>
0012 #include <linux/usb/hcd.h>
0013 #include <linux/greybus.h>
0014
0015 #include "gbphy.h"
0016
0017
0018 #define GB_USB_TYPE_HCD_START 0x02
0019 #define GB_USB_TYPE_HCD_STOP 0x03
0020 #define GB_USB_TYPE_HUB_CONTROL 0x04
0021
0022 struct gb_usb_hub_control_request {
0023 __le16 typeReq;
0024 __le16 wValue;
0025 __le16 wIndex;
0026 __le16 wLength;
0027 };
0028
0029 struct gb_usb_hub_control_response {
0030 u8 buf[0];
0031 };
0032
0033 struct gb_usb_device {
0034 struct gb_connection *connection;
0035 struct gbphy_device *gbphy_dev;
0036 };
0037
0038 static inline struct gb_usb_device *to_gb_usb_device(struct usb_hcd *hcd)
0039 {
0040 return (struct gb_usb_device *)hcd->hcd_priv;
0041 }
0042
0043 static inline struct usb_hcd *gb_usb_device_to_hcd(struct gb_usb_device *dev)
0044 {
0045 return container_of((void *)dev, struct usb_hcd, hcd_priv);
0046 }
0047
0048 static void hcd_stop(struct usb_hcd *hcd)
0049 {
0050 struct gb_usb_device *dev = to_gb_usb_device(hcd);
0051 int ret;
0052
0053 ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_STOP,
0054 NULL, 0, NULL, 0);
0055 if (ret)
0056 dev_err(&dev->gbphy_dev->dev, "HCD stop failed '%d'\n", ret);
0057 }
0058
0059 static int hcd_start(struct usb_hcd *hcd)
0060 {
0061 struct usb_bus *bus = hcd_to_bus(hcd);
0062 struct gb_usb_device *dev = to_gb_usb_device(hcd);
0063 int ret;
0064
0065 ret = gb_operation_sync(dev->connection, GB_USB_TYPE_HCD_START,
0066 NULL, 0, NULL, 0);
0067 if (ret) {
0068 dev_err(&dev->gbphy_dev->dev, "HCD start failed '%d'\n", ret);
0069 return ret;
0070 }
0071
0072 hcd->state = HC_STATE_RUNNING;
0073 if (bus->root_hub)
0074 usb_hcd_resume_root_hub(hcd);
0075 return 0;
0076 }
0077
0078 static int urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
0079 {
0080 return -ENXIO;
0081 }
0082
0083 static int urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
0084 {
0085 return -ENXIO;
0086 }
0087
0088 static int get_frame_number(struct usb_hcd *hcd)
0089 {
0090 return 0;
0091 }
0092
0093 static int hub_status_data(struct usb_hcd *hcd, char *buf)
0094 {
0095 return 0;
0096 }
0097
0098 static int hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
0099 char *buf, u16 wLength)
0100 {
0101 struct gb_usb_device *dev = to_gb_usb_device(hcd);
0102 struct gb_operation *operation;
0103 struct gb_usb_hub_control_request *request;
0104 struct gb_usb_hub_control_response *response;
0105 size_t response_size;
0106 int ret;
0107
0108
0109 response_size = sizeof(*response) + wLength;
0110
0111 operation = gb_operation_create(dev->connection,
0112 GB_USB_TYPE_HUB_CONTROL,
0113 sizeof(*request),
0114 response_size,
0115 GFP_KERNEL);
0116 if (!operation)
0117 return -ENOMEM;
0118
0119 request = operation->request->payload;
0120 request->typeReq = cpu_to_le16(typeReq);
0121 request->wValue = cpu_to_le16(wValue);
0122 request->wIndex = cpu_to_le16(wIndex);
0123 request->wLength = cpu_to_le16(wLength);
0124
0125 ret = gb_operation_request_send_sync(operation);
0126 if (ret)
0127 goto out;
0128
0129 if (wLength) {
0130
0131 response = operation->response->payload;
0132 memcpy(buf, response->buf, wLength);
0133 }
0134 out:
0135 gb_operation_put(operation);
0136
0137 return ret;
0138 }
0139
0140 static const struct hc_driver usb_gb_hc_driver = {
0141 .description = "greybus-hcd",
0142 .product_desc = "Greybus USB Host Controller",
0143 .hcd_priv_size = sizeof(struct gb_usb_device),
0144
0145 .flags = HCD_USB2,
0146
0147 .start = hcd_start,
0148 .stop = hcd_stop,
0149
0150 .urb_enqueue = urb_enqueue,
0151 .urb_dequeue = urb_dequeue,
0152
0153 .get_frame_number = get_frame_number,
0154 .hub_status_data = hub_status_data,
0155 .hub_control = hub_control,
0156 };
0157
0158 static int gb_usb_probe(struct gbphy_device *gbphy_dev,
0159 const struct gbphy_device_id *id)
0160 {
0161 struct gb_connection *connection;
0162 struct device *dev = &gbphy_dev->dev;
0163 struct gb_usb_device *gb_usb_dev;
0164 struct usb_hcd *hcd;
0165 int retval;
0166
0167 hcd = usb_create_hcd(&usb_gb_hc_driver, dev, dev_name(dev));
0168 if (!hcd)
0169 return -ENOMEM;
0170
0171 connection = gb_connection_create(gbphy_dev->bundle,
0172 le16_to_cpu(gbphy_dev->cport_desc->id),
0173 NULL);
0174 if (IS_ERR(connection)) {
0175 retval = PTR_ERR(connection);
0176 goto exit_usb_put;
0177 }
0178
0179 gb_usb_dev = to_gb_usb_device(hcd);
0180 gb_usb_dev->connection = connection;
0181 gb_connection_set_data(connection, gb_usb_dev);
0182 gb_usb_dev->gbphy_dev = gbphy_dev;
0183 gb_gbphy_set_data(gbphy_dev, gb_usb_dev);
0184
0185 hcd->has_tt = 1;
0186
0187 retval = gb_connection_enable(connection);
0188 if (retval)
0189 goto exit_connection_destroy;
0190
0191
0192
0193
0194
0195
0196
0197 if (1) {
0198 dev_warn(dev, "USB protocol disabled\n");
0199 retval = -EPROTONOSUPPORT;
0200 goto exit_connection_disable;
0201 }
0202
0203 retval = usb_add_hcd(hcd, 0, 0);
0204 if (retval)
0205 goto exit_connection_disable;
0206
0207 return 0;
0208
0209 exit_connection_disable:
0210 gb_connection_disable(connection);
0211 exit_connection_destroy:
0212 gb_connection_destroy(connection);
0213 exit_usb_put:
0214 usb_put_hcd(hcd);
0215
0216 return retval;
0217 }
0218
0219 static void gb_usb_remove(struct gbphy_device *gbphy_dev)
0220 {
0221 struct gb_usb_device *gb_usb_dev = gb_gbphy_get_data(gbphy_dev);
0222 struct gb_connection *connection = gb_usb_dev->connection;
0223 struct usb_hcd *hcd = gb_usb_device_to_hcd(gb_usb_dev);
0224
0225 usb_remove_hcd(hcd);
0226 gb_connection_disable(connection);
0227 gb_connection_destroy(connection);
0228 usb_put_hcd(hcd);
0229 }
0230
0231 static const struct gbphy_device_id gb_usb_id_table[] = {
0232 { GBPHY_PROTOCOL(GREYBUS_PROTOCOL_USB) },
0233 { },
0234 };
0235 MODULE_DEVICE_TABLE(gbphy, gb_usb_id_table);
0236
0237 static struct gbphy_driver usb_driver = {
0238 .name = "usb",
0239 .probe = gb_usb_probe,
0240 .remove = gb_usb_remove,
0241 .id_table = gb_usb_id_table,
0242 };
0243
0244 module_gbphy_driver(usb_driver);
0245 MODULE_LICENSE("GPL v2");