coreboot-kgpe-d16/payloads/libpayload/include/udc/udc.h
Patrick Georgi ea0bdf2d54 libpayload: Add zero length packet support to UDC framework
Some IN transfers must be terminated by an empty packet
because otherwise the host wouldn't know.

The zlp() function determines this requirement in
accordance to USB rules: If the transfer's size is aligned
to the maximum packet size, and the host expects a larger
transfer, add the empty packet as a hint.

BRANCH=none
BUG=none
TEST=USB device mode still works

Change-Id: Ia69f3d017f72a3a0e0b21bac72fe97be184c7daa
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: fd0e946e4948a74a9ed15a5eed6ce827b7672a56
Original-Change-Id: I8153cc5bd2ff1c88e383c1dbcddaf1bf72f9194c
Original-Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/250790
Original-Reviewed-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-on: http://review.coreboot.org/9784
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
2015-04-18 08:40:28 +02:00

143 lines
4.4 KiB
C

/*
* This file is part of the libpayload project.
*
* Copyright (C) 2015 Google Inc.
*
* 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.
* 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 name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#ifndef __UDC_H__
#define __UDC_H__
#include <queue.h>
#include <usb/usb.h>
struct usbdev_ctrl;
struct usbdev_interface {
interface_descriptor_t descriptor;
void (*init)(struct usbdev_ctrl *);
/**
* handle_packet: called by the controller driver for incoming packets
*
* @param ep endpoint the packet is for
*
* @param in_dir 1, if it's an IN or INTR transfer.
* 0 for OUT, SETUP is handled in handle_setup
*
* @param len Actual transfer length in bytes. Can differ from the
* scheduled length if the host requested a smaller
* transfer than we prepared for.
*/
void (*handle_packet)(struct usbdev_ctrl *, int ep, int in_dir,
void *data, int len);
/**
* handle_setup: called by the controller driver for setup packets
*
* @param ep endpoint the SETUP request came up on
* @param dr SETUP request data
*/
int (*handle_setup)(struct usbdev_ctrl *, int ep, dev_req_t *dr);
endpoint_descriptor_t *eps;
};
struct usbdev_configuration {
configuration_descriptor_t descriptor;
SLIST_ENTRY(usbdev_configuration) list;
struct usbdev_interface interfaces[];
};
SLIST_HEAD(configuration_list, usbdev_configuration);
struct usbdev_ctrl {
/* private data */
void *pdata;
int initialized;
int remote_wakeup;
struct usbdev_configuration *current_config;
struct usbdev_interface *current_iface;
int current_config_id;
struct configuration_list configs;
int config_count;
device_descriptor_t device_descriptor;
int ep_halted[16][2];
int ep_mps[16][2];
/** returns 0 if an error occurred */
int (*poll)(struct usbdev_ctrl *);
/**
* Add a gadget driver that exposes properties described in config.
*
* Each gadget driver is registered and exposed as separate USB
* "configuration", so the host can choose between them.
*/
void (*add_gadget)(struct usbdev_ctrl *,
struct usbdev_configuration *config);
/**
* Add packet to process by the controller.
* zlp: zero length packet, if such a termination is necessary
* autofree: free data after use
*/
void (*enqueue_packet)(struct usbdev_ctrl *this, int endpoint,
int in_dir, void *data, int len, int zlp, int autofree);
/**
* Tell the hardware that it should listen to a new address
*/
void (*set_address)(struct usbdev_ctrl *, int address);
void (*halt_ep)(struct usbdev_ctrl *this, int ep, int in_dir);
void (*start_ep)(struct usbdev_ctrl *this,
int ep, int in_dir, int ep_type, int mps);
/**
* Set or clear endpoint ep's STALL state
*/
void (*stall)(struct usbdev_ctrl *, uint8_t ep, int in_dir, int set);
void (*shutdown)(struct usbdev_ctrl *this);
/**
* Allocate n bytes for use as data
*/
void *(*alloc_data)(size_t n);
/**
* Free memory object allocated with alloc_data()
*/
void (*free_data)(void *);
};
void udc_add_gadget(struct usbdev_ctrl *this,
struct usbdev_configuration *config);
void udc_handle_setup(struct usbdev_ctrl *this, int ep, dev_req_t *dr);
#endif