brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · 475f24f Raw
247 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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		0x0219#define GB_USB_TYPE_HCD_STOP		0x0320#define GB_USB_TYPE_HUB_CONTROL		0x0421 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	DECLARE_FLEX_ARRAY(u8, buf);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 to193	 *        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_DESCRIPTION("USB host driver for the Greybus 'generic' USB module");246MODULE_LICENSE("GPL v2");247