637 lines · 12.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0+/* * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> * Copyright (C) 2015-2016 Samsung Electronics *               Igor Kotrasinski <i.kotrasinsk@samsung.com> *               Krzysztof Opasiak <k.opasiak@samsung.com> */ #include <linux/device.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/platform_device.h>#include <linux/usb.h>#include <linux/usb/gadget.h>#include <linux/usb/hcd.h>#include <linux/kthread.h>#include <linux/file.h>#include <linux/byteorder/generic.h> #include "usbip_common.h"#include "vudc.h" #define VIRTUAL_ENDPOINTS (1 /* ep0 */ + 15 /* in eps */ + 15 /* out eps */) /* urb-related structures alloc / free */  static void free_urb(struct urb *urb){	if (!urb)		return; 	kfree(urb->setup_packet);	urb->setup_packet = NULL; 	kfree(urb->transfer_buffer);	urb->transfer_buffer = NULL; 	usb_free_urb(urb);} struct urbp *alloc_urbp(void){	struct urbp *urb_p; 	urb_p = kzalloc_obj(*urb_p);	if (!urb_p)		return urb_p; 	urb_p->urb = NULL;	urb_p->ep = NULL;	INIT_LIST_HEAD(&urb_p->urb_entry);	return urb_p;} static void free_urbp(struct urbp *urb_p){	kfree(urb_p);} void free_urbp_and_urb(struct urbp *urb_p){	if (!urb_p)		return;	free_urb(urb_p->urb);	free_urbp(urb_p);}  /* utilities ; almost verbatim from dummy_hcd.c */ /* called with spinlock held */static void nuke(struct vudc *udc, struct vep *ep){	struct vrequest	*req; 	while (!list_empty(&ep->req_queue)) {		req = list_first_entry(&ep->req_queue, struct vrequest,				       req_entry);		list_del_init(&req->req_entry);		req->req.status = -ESHUTDOWN; 		spin_unlock(&udc->lock);		usb_gadget_giveback_request(&ep->ep, &req->req);		spin_lock(&udc->lock);	}} /* caller must hold lock */static void stop_activity(struct vudc *udc){	int i;	struct urbp *urb_p, *tmp; 	udc->address = 0; 	for (i = 0; i < VIRTUAL_ENDPOINTS; i++)		nuke(udc, &udc->ep[i]); 	list_for_each_entry_safe(urb_p, tmp, &udc->urb_queue, urb_entry) {		list_del(&urb_p->urb_entry);		free_urbp_and_urb(urb_p);	}} struct vep *vudc_find_endpoint(struct vudc *udc, u8 address){	int i; 	if ((address & ~USB_DIR_IN) == 0)		return &udc->ep[0]; 	for (i = 1; i < VIRTUAL_ENDPOINTS; i++) {		struct vep *ep = &udc->ep[i]; 		if (!ep->desc)			continue;		if (ep->desc->bEndpointAddress == address)			return ep;	}	return NULL;} /* gadget ops */ static int vgadget_get_frame(struct usb_gadget *_gadget){	struct timespec64 now;	struct vudc *udc = usb_gadget_to_vudc(_gadget); 	ktime_get_ts64(&now);	return ((now.tv_sec - udc->start_time.tv_sec) * 1000 +		(now.tv_nsec - udc->start_time.tv_nsec) / NSEC_PER_MSEC)			& 0x7FF;} static int vgadget_set_selfpowered(struct usb_gadget *_gadget, int value){	struct vudc *udc = usb_gadget_to_vudc(_gadget); 	if (value)		udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);	else		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);	return 0;} static int vgadget_pullup(struct usb_gadget *_gadget, int value){	struct vudc *udc = usb_gadget_to_vudc(_gadget);	unsigned long flags;	int ret;  	spin_lock_irqsave(&udc->lock, flags);	value = !!value;	if (value == udc->pullup)		goto unlock; 	udc->pullup = value;	if (value) {		udc->gadget.speed = min_t(u8, USB_SPEED_HIGH,					   udc->driver->max_speed);		udc->ep[0].ep.maxpacket = 64;		/*		 * This is the first place where we can ask our		 * gadget driver for descriptors.		 */		ret = get_gadget_descs(udc);		if (ret) {			dev_err(&udc->gadget.dev, "Unable go get desc: %d", ret);			goto unlock;		} 		spin_unlock_irqrestore(&udc->lock, flags);		usbip_start_eh(&udc->ud);	} else {		/* Invalidate descriptors */		udc->desc_cached = 0; 		spin_unlock_irqrestore(&udc->lock, flags);		usbip_event_add(&udc->ud, VUDC_EVENT_REMOVED);		usbip_stop_eh(&udc->ud); /* Wait for eh completion */	} 	return 0; unlock:	spin_unlock_irqrestore(&udc->lock, flags);	return 0;} static int vgadget_udc_start(struct usb_gadget *g,		struct usb_gadget_driver *driver){	struct vudc *udc = usb_gadget_to_vudc(g);	unsigned long flags; 	spin_lock_irqsave(&udc->lock, flags);	udc->driver = driver;	udc->pullup = udc->connected = udc->desc_cached = 0;	spin_unlock_irqrestore(&udc->lock, flags); 	return 0;} static int vgadget_udc_stop(struct usb_gadget *g){	struct vudc *udc = usb_gadget_to_vudc(g);	unsigned long flags; 	spin_lock_irqsave(&udc->lock, flags);	udc->driver = NULL;	spin_unlock_irqrestore(&udc->lock, flags);	return 0;} static const struct usb_gadget_ops vgadget_ops = {	.get_frame	= vgadget_get_frame,	.set_selfpowered = vgadget_set_selfpowered,	.pullup		= vgadget_pullup,	.udc_start	= vgadget_udc_start,	.udc_stop	= vgadget_udc_stop,};  /* endpoint ops */ static int vep_enable(struct usb_ep *_ep,		const struct usb_endpoint_descriptor *desc){	struct vep	*ep;	struct vudc	*udc;	unsigned int	maxp;	unsigned long	flags; 	ep = to_vep(_ep);	udc = ep_to_vudc(ep); 	if (!_ep || !desc || ep->desc || _ep->caps.type_control			|| desc->bDescriptorType != USB_DT_ENDPOINT)		return -EINVAL; 	if (!udc->driver)		return -ESHUTDOWN; 	spin_lock_irqsave(&udc->lock, flags); 	maxp = usb_endpoint_maxp(desc);	_ep->maxpacket = maxp;	ep->desc = desc;	ep->type = usb_endpoint_type(desc);	ep->halted = ep->wedged = 0; 	spin_unlock_irqrestore(&udc->lock, flags); 	return 0;} static int vep_disable(struct usb_ep *_ep){	struct vep *ep;	struct vudc *udc;	unsigned long flags; 	ep = to_vep(_ep);	udc = ep_to_vudc(ep);	if (!_ep || !ep->desc || _ep->caps.type_control)		return -EINVAL; 	spin_lock_irqsave(&udc->lock, flags);	ep->desc = NULL;	nuke(udc, ep);	spin_unlock_irqrestore(&udc->lock, flags); 	return 0;} static struct usb_request *vep_alloc_request(struct usb_ep *_ep,		gfp_t mem_flags){	struct vrequest *req; 	if (!_ep)		return NULL; 	req = kzalloc_obj(*req, mem_flags);	if (!req)		return NULL; 	INIT_LIST_HEAD(&req->req_entry); 	return &req->req;} static void vep_free_request(struct usb_ep *_ep, struct usb_request *_req){	struct vrequest *req; 	/* ep is always valid here - see usb_ep_free_request() */	if (!_req)		return; 	req = to_vrequest(_req);	kfree(req);} static int vep_queue(struct usb_ep *_ep, struct usb_request *_req,		gfp_t mem_flags){	struct vep *ep;	struct vrequest *req;	struct vudc *udc;	unsigned long flags; 	if (!_ep || !_req)		return -EINVAL; 	ep = to_vep(_ep);	req = to_vrequest(_req);	udc = ep_to_vudc(ep); 	spin_lock_irqsave(&udc->lock, flags);	_req->actual = 0;	_req->status = -EINPROGRESS; 	list_add_tail(&req->req_entry, &ep->req_queue);	spin_unlock_irqrestore(&udc->lock, flags); 	return 0;} static int vep_dequeue(struct usb_ep *_ep, struct usb_request *_req){	struct vep *ep;	struct vudc *udc;	struct vrequest *lst;	unsigned long flags;	int ret = -EINVAL; 	if (!_ep || !_req)		return ret; 	ep = to_vep(_ep);	udc = ep_to_vudc(ep); 	if (!udc->driver)		return -ESHUTDOWN; 	spin_lock_irqsave(&udc->lock, flags);	list_for_each_entry(lst, &ep->req_queue, req_entry) {		if (&lst->req == _req) {			list_del_init(&lst->req_entry);			_req->status = -ECONNRESET;			ret = 0;			break;		}	}	spin_unlock_irqrestore(&udc->lock, flags); 	if (ret == 0)		usb_gadget_giveback_request(_ep, _req); 	return ret;} static intvep_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged){	struct vep *ep;	struct vudc *udc;	unsigned long flags;	int ret = 0; 	ep = to_vep(_ep);	if (!_ep)		return -EINVAL; 	udc = ep_to_vudc(ep);	if (!udc->driver)		return -ESHUTDOWN; 	spin_lock_irqsave(&udc->lock, flags);	if (!value)		ep->halted = ep->wedged = 0;	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&			!list_empty(&ep->req_queue))		ret = -EAGAIN;	else {		ep->halted = 1;		if (wedged)			ep->wedged = 1;	} 	spin_unlock_irqrestore(&udc->lock, flags);	return ret;} static intvep_set_halt(struct usb_ep *_ep, int value){	return vep_set_halt_and_wedge(_ep, value, 0);} static int vep_set_wedge(struct usb_ep *_ep){	return vep_set_halt_and_wedge(_ep, 1, 1);} static const struct usb_ep_ops vep_ops = {	.enable		= vep_enable,	.disable	= vep_disable, 	.alloc_request	= vep_alloc_request,	.free_request	= vep_free_request, 	.queue		= vep_queue,	.dequeue	= vep_dequeue, 	.set_halt	= vep_set_halt,	.set_wedge	= vep_set_wedge,};  /* shutdown / reset / error handlers */ static void vudc_shutdown(struct usbip_device *ud){	struct vudc *udc = container_of(ud, struct vudc, ud);	int call_disconnect = 0;	unsigned long flags; 	dev_dbg(&udc->pdev->dev, "device shutdown");	if (ud->tcp_socket)		kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); 	if (ud->tcp_rx) {		kthread_stop_put(ud->tcp_rx);		ud->tcp_rx = NULL;	}	if (ud->tcp_tx) {		kthread_stop_put(ud->tcp_tx);		ud->tcp_tx = NULL;	} 	if (ud->tcp_socket) {		sockfd_put(ud->tcp_socket);		ud->tcp_socket = NULL;	} 	spin_lock_irqsave(&udc->lock, flags);	stop_activity(udc);	if (udc->connected && udc->driver->disconnect)		call_disconnect = 1;	udc->connected = 0;	spin_unlock_irqrestore(&udc->lock, flags);	if (call_disconnect)		udc->driver->disconnect(&udc->gadget);} static void vudc_device_reset(struct usbip_device *ud){	struct vudc *udc = container_of(ud, struct vudc, ud);	unsigned long flags; 	dev_dbg(&udc->pdev->dev, "device reset");	spin_lock_irqsave(&udc->lock, flags);	stop_activity(udc);	spin_unlock_irqrestore(&udc->lock, flags);	if (udc->driver)		usb_gadget_udc_reset(&udc->gadget, udc->driver);	spin_lock_irqsave(&ud->lock, flags);	ud->status = SDEV_ST_AVAILABLE;	spin_unlock_irqrestore(&ud->lock, flags);} static void vudc_device_unusable(struct usbip_device *ud){	unsigned long flags; 	spin_lock_irqsave(&ud->lock, flags);	ud->status = SDEV_ST_ERROR;	spin_unlock_irqrestore(&ud->lock, flags);} /* device setup / cleanup */ struct vudc_device *alloc_vudc_device(int devid){	struct vudc_device *udc_dev; 	udc_dev = kzalloc_obj(*udc_dev);	if (!udc_dev)		return NULL; 	INIT_LIST_HEAD(&udc_dev->dev_entry); 	udc_dev->pdev = platform_device_alloc(GADGET_NAME, devid);	if (!udc_dev->pdev) {		kfree(udc_dev);

Lines 1–500 of 637.