linux/drivers/usb/gadget/udc/dummy_hcd.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * dummy_hcd.c -- Dummy/Loopback USB host and device emulator driver.
 *
 * Maintainer: Alan Stern <[email protected]>
 *
 * Copyright (C) 2003 David Brownell
 * Copyright (C) 2003-2005 Alan Stern
 */


/*
 * This exposes a device side "USB gadget" API, driven by requests to a
 * Linux-USB host controller driver.  USB traffic is simulated; there's
 * no need for USB hardware.  Use this with two other drivers:
 *
 *  - Gadget driver, responding to requests (device);
 *  - Host-side device driver, as already familiar in Linux.
 *
 * Having this all in one kernel can help some stages of development,
 * bypassing some hardware (and driver) issues.  UML could help too.
 *
 * Note: The emulation does not include isochronous transfers!
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/hrtimer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb/gadget.h>
#include <linux/usb/hcd.h>
#include <linux/scatterlist.h>

#include <asm/byteorder.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <asm/unaligned.h>

#define DRIVER_DESC
#define DRIVER_VERSION

#define POWER_BUDGET
#define POWER_BUDGET_3

#define DUMMY_TIMER_INT_NSECS

static const char	driver_name[] =;
static const char	driver_desc[] =;

static const char	gadget_name[] =;

MODULE_DESCRIPTION();
MODULE_AUTHOR();
MODULE_LICENSE();

struct dummy_hcd_module_parameters {};

static struct dummy_hcd_module_parameters mod_data =;
module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
MODULE_PARM_DESC();
module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
MODULE_PARM_DESC();
module_param_named(num, mod_data.num, uint, S_IRUGO);
MODULE_PARM_DESC();
/*-------------------------------------------------------------------------*/

/* gadget side driver data structres */
struct dummy_ep {};

struct dummy_request {};

static inline struct dummy_ep *usb_ep_to_dummy_ep(struct usb_ep *_ep)
{}

static inline struct dummy_request *usb_request_to_dummy_request
		(struct usb_request *_req)
{}

/*-------------------------------------------------------------------------*/

/*
 * Every device has ep0 for control requests, plus up to 30 more endpoints,
 * in one of two types:
 *
 *   - Configurable:  direction (in/out), type (bulk, iso, etc), and endpoint
 *     number can be changed.  Names like "ep-a" are used for this type.
 *
 *   - Fixed Function:  in other cases.  some characteristics may be mutable;
 *     that'd be hardware-specific.  Names like "ep12out-bulk" are used.
 *
 * Gadget drivers are responsible for not setting up conflicting endpoint
 * configurations, illegal or unsupported packet lengths, and so on.
 */

static const char ep0name[] =;

static const struct {} ep_info[] =;

#define DUMMY_ENDPOINTS

/*-------------------------------------------------------------------------*/

#define FIFO_SIZE

struct urbp {};


enum dummy_rh_state {};

struct dummy_hcd {};

struct dummy {};

static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
{}

static inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
{}

static inline struct device *dummy_dev(struct dummy_hcd *dum)
{}

static inline struct device *udc_dev(struct dummy *dum)
{}

static inline struct dummy *ep_to_dummy(struct dummy_ep *ep)
{}

static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
{}

static inline struct dummy *gadget_dev_to_dummy(struct device *dev)
{}

/*-------------------------------------------------------------------------*/

/* DEVICE/GADGET SIDE UTILITY ROUTINES */

/* called with spinlock held */
static void nuke(struct dummy *dum, struct dummy_ep *ep)
{}

/* caller must hold lock */
static void stop_activity(struct dummy *dum)
{}

/**
 * set_link_state_by_speed() - Sets the current state of the link according to
 *	the hcd speed
 * @dum_hcd: pointer to the dummy_hcd structure to update the link state for
 *
 * This function updates the port_status according to the link state and the
 * speed of the hcd.
 */
static void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
{}

/* caller must hold lock */
static void set_link_state(struct dummy_hcd *dum_hcd)
	__must_hold(&dum->lock)
{}

/*-------------------------------------------------------------------------*/

/* DEVICE/GADGET SIDE DRIVER
 *
 * This only tracks gadget state.  All the work is done when the host
 * side tries some (emulated) i/o operation.  Real device controller
 * drivers would do real i/o using dma, fifos, irqs, timers, etc.
 */

#define is_enabled

static int dummy_enable(struct usb_ep *_ep,
		const struct usb_endpoint_descriptor *desc)
{}

static int dummy_disable(struct usb_ep *_ep)
{}

static struct usb_request *dummy_alloc_request(struct usb_ep *_ep,
		gfp_t mem_flags)
{}

static void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req)
{}

static void fifo_complete(struct usb_ep *ep, struct usb_request *req)
{}

static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req,
		gfp_t mem_flags)
{}

static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{}

static int
dummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
{}

static int
dummy_set_halt(struct usb_ep *_ep, int value)
{}

static int dummy_set_wedge(struct usb_ep *_ep)
{}

static const struct usb_ep_ops dummy_ep_ops =;

/*-------------------------------------------------------------------------*/

/* there are both host and device side versions of this call ... */
static int dummy_g_get_frame(struct usb_gadget *_gadget)
{}

static int dummy_wakeup(struct usb_gadget *_gadget)
{}

static int dummy_set_selfpowered(struct usb_gadget *_gadget, int value)
{}

static void dummy_udc_update_ep0(struct dummy *dum)
{}

static int dummy_pullup(struct usb_gadget *_gadget, int value)
{}

static void dummy_udc_set_speed(struct usb_gadget *_gadget,
		enum usb_device_speed speed)
{}

static void dummy_udc_async_callbacks(struct usb_gadget *_gadget, bool enable)
{}

static int dummy_udc_start(struct usb_gadget *g,
		struct usb_gadget_driver *driver);
static int dummy_udc_stop(struct usb_gadget *g);

static const struct usb_gadget_ops dummy_ops =;

/*-------------------------------------------------------------------------*/

/* "function" sysfs attribute */
static ssize_t function_show(struct device *dev, struct device_attribute *attr,
		char *buf)
{}
static DEVICE_ATTR_RO(function);

/*-------------------------------------------------------------------------*/

/*
 * Driver registration/unregistration.
 *
 * This is basically hardware-specific; there's usually only one real USB
 * device (not host) controller since that's how USB devices are intended
 * to work.  So most implementations of these api calls will rely on the
 * fact that only one driver will ever bind to the hardware.  But curious
 * hardware can be built with discrete components, so the gadget API doesn't
 * require that assumption.
 *
 * For this emulator, it might be convenient to create a usb device
 * for each driver that registers:  just add to a big root hub.
 */

static int dummy_udc_start(struct usb_gadget *g,
		struct usb_gadget_driver *driver)
{}

static int dummy_udc_stop(struct usb_gadget *g)
{}

#undef is_enabled

/* The gadget structure is stored inside the hcd structure and will be
 * released along with it. */
static void init_dummy_udc_hw(struct dummy *dum)
{}

static int dummy_udc_probe(struct platform_device *pdev)
{}

static void dummy_udc_remove(struct platform_device *pdev)
{}

static void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd,
		int suspend)
{}

static int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state)
{}

static int dummy_udc_resume(struct platform_device *pdev)
{}

static struct platform_driver dummy_udc_driver =;

/*-------------------------------------------------------------------------*/

static unsigned int dummy_get_ep_idx(const struct usb_endpoint_descriptor *desc)
{}

/* HOST SIDE DRIVER
 *
 * this uses the hcd framework to hook up to host side drivers.
 * its root hub will only have one device, otherwise it acts like
 * a normal host controller.
 *
 * when urbs are queued, they're just stuck on a list that we
 * scan in a timer callback.  that callback connects writes from
 * the host with reads from the device, and so on, based on the
 * usb 2.0 rules.
 */

static int dummy_ep_stream_en(struct dummy_hcd *dum_hcd, struct urb *urb)
{}

/*
 * The max stream number is saved as a nibble so for the 30 possible endpoints
 * we only 15 bytes of memory. Therefore we are limited to max 16 streams (0
 * means we use only 1 stream). The maximum according to the spec is 16bit so
 * if the 16 stream limit is about to go, the array size should be incremented
 * to 30 elements of type u16.
 */
static int get_max_streams_for_pipe(struct dummy_hcd *dum_hcd,
		unsigned int pipe)
{}

static void set_max_streams_for_pipe(struct dummy_hcd *dum_hcd,
		unsigned int pipe, unsigned int streams)
{}

static int dummy_validate_stream(struct dummy_hcd *dum_hcd, struct urb *urb)
{}

static int dummy_urb_enqueue(
	struct usb_hcd			*hcd,
	struct urb			*urb,
	gfp_t				mem_flags
) {}

static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{}

static int dummy_perform_transfer(struct urb *urb, struct dummy_request *req,
		u32 len)
{}

/* transfer up to a frame's worth; caller must own lock */
static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
		struct dummy_ep *ep, int limit, int *status)
{}

static int periodic_bytes(struct dummy *dum, struct dummy_ep *ep)
{}

#define is_active

static struct dummy_ep *find_endpoint(struct dummy *dum, u8 address)
{}

#undef is_active

#define Dev_Request
#define Dev_InRequest
#define Intf_Request
#define Intf_InRequest
#define Ep_Request
#define Ep_InRequest


/**
 * handle_control_request() - handles all control transfers
 * @dum_hcd: pointer to dummy (the_controller)
 * @urb: the urb request to handle
 * @setup: pointer to the setup data for a USB device control
 *	 request
 * @status: pointer to request handling status
 *
 * Return 0 - if the request was handled
 *	  1 - if the request wasn't handles
 *	  error code on error
 */
static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
				  struct usb_ctrlrequest *setup,
				  int *status)
{}

/*
 * Drive both sides of the transfers; looks like irq handlers to both
 * drivers except that the callbacks are invoked from soft interrupt
 * context.
 */
static enum hrtimer_restart dummy_timer(struct hrtimer *t)
{}

/*-------------------------------------------------------------------------*/

#define PORT_C_MASK

static int dummy_hub_status(struct usb_hcd *hcd, char *buf)
{}

/* usb 3.0 root hub device descriptor */
static struct {} __packed usb3_bos_desc =;

static inline void
ss_hub_descriptor(struct usb_hub_descriptor *desc)
{}

static inline void hub_descriptor(struct usb_hub_descriptor *desc)
{}

static int dummy_hub_control(
	struct usb_hcd	*hcd,
	u16		typeReq,
	u16		wValue,
	u16		wIndex,
	char		*buf,
	u16		wLength
) {}

static int dummy_bus_suspend(struct usb_hcd *hcd)
{}

static int dummy_bus_resume(struct usb_hcd *hcd)
{}

/*-------------------------------------------------------------------------*/

static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)
{}

static ssize_t urbs_show(struct device *dev, struct device_attribute *attr,
		char *buf)
{}
static DEVICE_ATTR_RO(urbs);

static int dummy_start_ss(struct dummy_hcd *dum_hcd)
{}

static int dummy_start(struct usb_hcd *hcd)
{}

static void dummy_stop(struct usb_hcd *hcd)
{}

/*-------------------------------------------------------------------------*/

static int dummy_h_get_frame(struct usb_hcd *hcd)
{}

static int dummy_setup(struct usb_hcd *hcd)
{}

/* Change a group of bulk endpoints to support multiple stream IDs */
static int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
	struct usb_host_endpoint **eps, unsigned int num_eps,
	unsigned int num_streams, gfp_t mem_flags)
{}

/* Reverts a group of bulk endpoints back to not using stream IDs. */
static int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
	struct usb_host_endpoint **eps, unsigned int num_eps,
	gfp_t mem_flags)
{}

static struct hc_driver dummy_hcd =;

static int dummy_hcd_probe(struct platform_device *pdev)
{}

static void dummy_hcd_remove(struct platform_device *pdev)
{}

static int dummy_hcd_suspend(struct platform_device *pdev, pm_message_t state)
{}

static int dummy_hcd_resume(struct platform_device *pdev)
{}

static struct platform_driver dummy_hcd_driver =;

/*-------------------------------------------------------------------------*/
#define MAX_NUM_UDC
static struct platform_device *the_udc_pdev[MAX_NUM_UDC];
static struct platform_device *the_hcd_pdev[MAX_NUM_UDC];

static int __init dummy_hcd_init(void)
{}
module_init();

static void __exit dummy_hcd_cleanup(void)
{}
module_exit(dummy_hcd_cleanup);