cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

usb.c (5623B)


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