📄 zero.c
字号:
/*
* zero.c -- Gadget Zero, for USB development
*
* Copyright (C) 2003-2004 David Brownell
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that License or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* 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.
*
* Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
* affect most of the driver.
*
* Use it with the Linux host/master 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. Module options include:
*
* buflen=N default N=4096, buffer size used
* qlen=N default N=32, how many buffers in the loopback queue
* loopdefault default false, list loopback config first
*
* 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).
*/
#define DEBUG 1
// #define VERBOSE
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/utsname.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
/*-------------------------------------------------------------------------*/
#define DRIVER_VERSION "St Patrick's Day 2004"
static const char shortname [] = "zero";
static const char longname [] = "Gadget Zero";
static const char source_sink [] = "source and sink data";
static const char loopback [] = "loop input to output";
/*-------------------------------------------------------------------------*/
/*
* driver assumes self-powered hardware, and
* has no way for users to trigger remote wakeup.
*
* this version autoconfigures as much as possible,
* which is reasonable for most "bulk-only" drivers.
*/
static const char *EP_IN_NAME; /* source */
static const char *EP_OUT_NAME; /* sink */
/*-------------------------------------------------------------------------*/
/* big enough to hold our biggest descriptor */
#define USB_BUFSIZ 256
struct zero_dev {
spinlock_t lock;
struct usb_gadget *gadget;
struct usb_request *req; /* for control responses */
/* when configured, we have one of two configs:
* - source data (in to host) and sink it (out from host)
* - or loop it back (out from host back in to host)
*/
u8 config;
struct usb_ep *in_ep, *out_ep;
/* autoresume timer */
struct timer_list resume;
};
#define xprintk(d,level,fmt,args...) \
dev_printk(level , &(d)->gadget->dev , fmt , ## args)
#ifdef DEBUG
#define DBG(dev,fmt,args...) \
xprintk(dev , KERN_DEBUG , fmt , ## args)
#else
#define DBG(dev,fmt,args...) \
do { } while (0)
#endif /* DEBUG */
#ifdef VERBOSE
#define VDBG DBG
#else
#define VDBG(dev,fmt,args...) \
do { } while (0)
#endif /* VERBOSE */
#define ERROR(dev,fmt,args...) \
xprintk(dev , KERN_ERR , fmt , ## args)
#define WARN(dev,fmt,args...) \
xprintk(dev , KERN_WARNING , fmt , ## args)
#define INFO(dev,fmt,args...) \
xprintk(dev , KERN_INFO , fmt , ## args)
/*-------------------------------------------------------------------------*/
static unsigned buflen = 4096;
static unsigned qlen = 32;
static unsigned pattern = 0;
module_param (buflen, uint, S_IRUGO|S_IWUSR);
module_param (qlen, uint, S_IRUGO|S_IWUSR);
module_param (pattern, uint, S_IRUGO|S_IWUSR);
/*
* if it's nonzero, autoresume says how many seconds to wait
* before trying to wake up the host after suspend.
*/
static unsigned autoresume = 0;
module_param (autoresume, uint, 0);
/*
* 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 superh) that only support one config.
*/
static int loopdefault = 0;
module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
/*-------------------------------------------------------------------------*/
/* 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 0x0525 /* NetChip */
#define DRIVER_PRODUCT_NUM 0xa4a0 /* Linux-USB "Gadget Zero" */
#else
#define DRIVER_VENDOR_NUM 0x1a0a /* OTG test device IDs */
#define DRIVER_PRODUCT_NUM 0xbadd
#endif
/*-------------------------------------------------------------------------*/
/*
* DESCRIPTORS ... most are static, but strings and (full)
* configuration descriptors are built on demand.
*/
#define STRING_MANUFACTURER 25
#define STRING_PRODUCT 42
#define STRING_SERIAL 101
#define STRING_SOURCE_SINK 250
#define STRING_LOOPBACK 251
/*
* This device advertises two configurations; these numbers work
* on a pxa250 as well as more flexible hardware.
*/
#define CONFIG_SOURCE_SINK 3
#define CONFIG_LOOPBACK 2
static struct usb_device_descriptor
device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = __constant_cpu_to_le16 (0x0200),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
.idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
.idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
.iManufacturer = STRING_MANUFACTURER,
.iProduct = STRING_PRODUCT,
.iSerialNumber = STRING_SERIAL,
.bNumConfigurations = 2,
};
static struct usb_config_descriptor
source_sink_config = {
.bLength = sizeof source_sink_config,
.bDescriptorType = USB_DT_CONFIG,
/* compute wTotalLength on the fly */
.bNumInterfaces = 1,
.bConfigurationValue = CONFIG_SOURCE_SINK,
.iConfiguration = STRING_SOURCE_SINK,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bMaxPower = 1, /* self-powered */
};
static struct usb_config_descriptor
loopback_config = {
.bLength = sizeof loopback_config,
.bDescriptorType = USB_DT_CONFIG,
/* compute wTotalLength on the fly */
.bNumInterfaces = 1,
.bConfigurationValue = CONFIG_LOOPBACK,
.iConfiguration = STRING_LOOPBACK,
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bMaxPower = 1, /* self-powered */
};
static struct usb_otg_descriptor
otg_descriptor = {
.bLength = sizeof otg_descriptor,
.bDescriptorType = USB_DT_OTG,
.bmAttributes = USB_OTG_SRP,
};
/* one interface in each configuration */
static const struct usb_interface_descriptor
source_sink_intf = {
.bLength = sizeof source_sink_intf,
.bDescriptorType = USB_DT_INTERFACE,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.iInterface = STRING_SOURCE_SINK,
};
static const struct usb_interface_descriptor
loopback_intf = {
.bLength = sizeof loopback_intf,
.bDescriptorType = USB_DT_INTERFACE,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.iInterface = STRING_LOOPBACK,
};
/* two full speed bulk endpoints; their use is config-dependent */
static struct usb_endpoint_descriptor
fs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
static struct usb_endpoint_descriptor
fs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
static const struct usb_descriptor_header *fs_source_sink_function [] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &source_sink_intf,
(struct usb_descriptor_header *) &fs_sink_desc,
(struct usb_descriptor_header *) &fs_source_desc,
NULL,
};
static const struct usb_descriptor_header *fs_loopback_function [] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &fs_sink_desc,
(struct usb_descriptor_header *) &fs_source_desc,
NULL,
};
#ifdef CONFIG_USB_GADGET_DUALSPEED
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
*
* that means alternate endpoint descriptors (bigger packets)
* and a "device qualifier" ... plus more construction options
* for the config descriptor.
*/
static struct usb_endpoint_descriptor
hs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16 (512),
};
static struct usb_endpoint_descriptor
hs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = __constant_cpu_to_le16 (512),
};
static struct usb_qualifier_descriptor
dev_qualifier = {
.bLength = sizeof dev_qualifier,
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
.bcdUSB = __constant_cpu_to_le16 (0x0200),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
.bNumConfigurations = 2,
};
static const struct usb_descriptor_header *hs_source_sink_function [] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &source_sink_intf,
(struct usb_descriptor_header *) &hs_source_desc,
(struct usb_descriptor_header *) &hs_sink_desc,
NULL,
};
static const struct usb_descriptor_header *hs_loopback_function [] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &hs_source_desc,
(struct usb_descriptor_header *) &hs_sink_desc,
NULL,
};
/* maxpacket and other transfer characteristics vary by speed. */
#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
#else
/* if there's no high speed support, maxpacket doesn't change. */
#define ep_desc(g,hs,fs) fs
#endif /* !CONFIG_USB_GADGET_DUALSPEED */
static char manufacturer [50];
static char serial [40];
/* static strings, in UTF-8 */
static struct usb_string strings [] = {
{ STRING_MANUFACTURER, manufacturer, },
{ STRING_PRODUCT, longname, },
{ STRING_SERIAL, serial, },
{ STRING_LOOPBACK, loopback, },
{ STRING_SOURCE_SINK, source_sink, },
{ } /* end of list */
};
static struct usb_gadget_strings stringtab = {
.language = 0x0409, /* en-us */
.strings = strings,
};
/*
* config descriptors are also handcrafted. these must agree with code
* that sets configurations, and with code managing interfaces and their
* altsettings. other complexity may come from:
*
* - high speed support, including "other speed config" rules
* - multiple configurations
* - interfaces with alternate settings
* - embedded class or vendor-specific descriptors
*
* this handles high speed, and has a second config that could as easily
* have been an alternate interface setting (on most hardware).
*
* NOTE: to demonstrate (and test) more USB capabilities, this driver
* should include an altsetting to test interrupt transfers, including
* high bandwidth modes at high speed. (Maybe work like Intel's test
* device?)
*/
static int
config_buf (struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index)
{
int is_source_sink;
int len;
const struct usb_descriptor_header **function;
#ifdef CONFIG_USB_GADGET_DUALSPEED
int hs = (gadget->speed == USB_SPEED_HIGH);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -