linux/drivers/usb/gadget/legacy/zero.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * zero.c -- Gadget Zero, for USB development
 *
 * Copyright (C) 2003-2008 David Brownell
 * Copyright (C) 2008 by Nokia Corporation
 */

/*
 * Gadget Zero only needs two bulk endpoints, and is an example of how you
 * can write a hardware-agnostic gadget driver running inside a USB device.
 * Some hardware details are visible, but don't affect most of the driver.
 *
 * Use it with the Linux host side "usbtest" driver to get a basic functional
 * test of your device-side usb stack, or with "usb-skeleton".
 *
 * It supports two similar configurations.  One sinks whatever the usb host
 * writes, and in return sources zeroes.  The other loops whatever the host
 * writes back, so the host can read it.
 *
 * Many drivers will only have one configuration, letting them be much
 * simpler if they also don't support high speed operation (like this
 * driver does).
 *
 * Why is *this* driver using two configurations, rather than setting up
 * two interfaces with different functions?  To help verify that multiple
 * configuration infrastructure is working correctly; also, so that it can
 * work with low capability USB controllers without four bulk endpoints.
 */

/*
 * driver assumes self-powered hardware, and
 * has no way for users to trigger remote wakeup.
 */

/* #define VERBOSE_DEBUG */

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/usb/composite.h>

#include "g_zero.h"
/*-------------------------------------------------------------------------*/
USB_GADGET_COMPOSITE_OPTIONS();

#define DRIVER_VERSION

static const char longname[] =;

/*
 * Normally the "loopback" configuration is second (index 1) so
 * it's not the default.  Here's where to change that order, to
 * work better with hosts where config changes are problematic or
 * controllers (like original superh) that only support one config.
 */
static bool loopdefault =;
module_param(loopdefault, bool, S_IRUGO|S_IWUSR);

static struct usb_zero_options gzero_options =;

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

/* Thanks to NetChip Technologies for donating this product ID.
 *
 * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
 * Instead:  allocate your own, using normal USB-IF procedures.
 */
#ifndef	CONFIG_USB_ZERO_HNPTEST
#define DRIVER_VENDOR_NUM
#define DRIVER_PRODUCT_NUM
#define DEFAULT_AUTORESUME
#else
#define DRIVER_VENDOR_NUM
#define DRIVER_PRODUCT_NUM
#define DEFAULT_AUTORESUME
#endif

/* If the optional "autoresume" mode is enabled, it provides good
 * functional coverage for the "USBCV" test harness from USB-IF.
 * It's always set if OTG mode is enabled.
 */
static unsigned autoresume =;
module_param(autoresume, uint, S_IRUGO);
MODULE_PARM_DESC();

/* Maximum Autoresume time */
static unsigned max_autoresume;
module_param(max_autoresume, uint, S_IRUGO);
MODULE_PARM_DESC();

/* Interval between two remote wakeups */
static unsigned autoresume_interval_ms;
module_param(autoresume_interval_ms, uint, S_IRUGO);
MODULE_PARM_DESC();

static unsigned autoresume_step_ms;
/*-------------------------------------------------------------------------*/

static struct usb_device_descriptor device_desc =;

static const struct usb_descriptor_header *otg_desc[2];

/* string IDs are assigned dynamically */
/* default serial number takes at least two packets */
static char serial[] =;

#define USB_GZERO_SS_DESC
#define USB_GZERO_LB_DESC

static struct usb_string strings_dev[] =;

static struct usb_gadget_strings stringtab_dev =;

static struct usb_gadget_strings *dev_strings[] =;

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

static struct timer_list	autoresume_timer;
static struct usb_composite_dev *autoresume_cdev;

static void zero_autoresume(struct timer_list *unused)
{}

static void zero_suspend(struct usb_composite_dev *cdev)
{}

static void zero_resume(struct usb_composite_dev *cdev)
{}

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

static struct usb_configuration loopback_driver =;

static struct usb_function *func_ss;
static struct usb_function_instance *func_inst_ss;

static int ss_config_setup(struct usb_configuration *c,
		const struct usb_ctrlrequest *ctrl)
{}

static struct usb_configuration sourcesink_driver =;

module_param_named(buflen, gzero_options.bulk_buflen, uint, 0);
module_param_named(pattern, gzero_options.pattern, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC();

module_param_named(isoc_interval, gzero_options.isoc_interval, uint,
		S_IRUGO|S_IWUSR);
MODULE_PARM_DESC();

module_param_named(isoc_maxpacket, gzero_options.isoc_maxpacket, uint,
		S_IRUGO|S_IWUSR);
MODULE_PARM_DESC();

module_param_named(isoc_mult, gzero_options.isoc_mult, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC();

module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint,
		S_IRUGO|S_IWUSR);
MODULE_PARM_DESC();

static struct usb_function *func_lb;
static struct usb_function_instance *func_inst_lb;

module_param_named(qlen, gzero_options.qlen, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC();

module_param_named(ss_bulk_qlen, gzero_options.ss_bulk_qlen, uint,
		S_IRUGO|S_IWUSR);
MODULE_PARM_DESC();

module_param_named(ss_iso_qlen, gzero_options.ss_iso_qlen, uint,
		S_IRUGO|S_IWUSR);
MODULE_PARM_DESC();

static int zero_bind(struct usb_composite_dev *cdev)
{}

static int zero_unbind(struct usb_composite_dev *cdev)
{}

static struct usb_composite_driver zero_driver =;

module_usb_composite_driver();

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