Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * USB host driver for the Greybus "generic" USB module.
0004  *
0005  * Copyright 2014 Google Inc.
0006  * Copyright 2014 Linaro Ltd.
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 /* Greybus USB request types */
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     /* FIXME: handle unspecified lengths */
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         /* Greybus core has verified response size */
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      * FIXME: The USB bridged-PHY protocol driver depends on changes to
0193      *        USB core which are not yet upstream.
0194      *
0195      *        Disable for now.
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");