Stefan thinks they don't add value. Command used: sed -i -e '/file is part of /d' $(git grep "file is part of " |egrep ":( */\*.*\*/\$|#|;#|-- | *\* )" | cut -d: -f1 |grep -v crossgcc |grep -v gcov | grep -v /elf.h |grep -v nvramtool) The exceptions are for: - crossgcc (patch file) - gcov (imported from gcc) - elf.h (imported from GNU's libc) - nvramtool (more complicated header) The removed lines are: - fmt.Fprintln(f, "/* This file is part of the coreboot project. */") -# This file is part of a set of unofficial pre-commit hooks available -/* This file is part of coreboot */ -# This file is part of msrtool. -/* This file is part of msrtool. */ - * This file is part of ncurses, designed to be appended after curses.h.in -/* This file is part of pgtblgen. */ - * This file is part of the coreboot project. - /* This file is part of the coreboot project. */ -# This file is part of the coreboot project. -# This file is part of the coreboot project. -## This file is part of the coreboot project. --- This file is part of the coreboot project. -/* This file is part of the coreboot project */ -/* This file is part of the coreboot project. */ -;## This file is part of the coreboot project. -# This file is part of the coreboot project. It originated in the - * This file is part of the coreinfo project. -## This file is part of the coreinfo project. - * This file is part of the depthcharge project. -/* This file is part of the depthcharge project. */ -/* This file is part of the ectool project. */ - * This file is part of the GNU C Library. - * This file is part of the libpayload project. -## This file is part of the libpayload project. -/* This file is part of the Linux kernel. */ -## This file is part of the superiotool project. -/* This file is part of the superiotool project */ -/* This file is part of uio_usbdebug */ Change-Id: I82d872b3b337388c93d5f5bf704e9ee9e53ab3a9 Signed-off-by: Patrick Georgi <pgeorgi@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/41194 Reviewed-by: HAOUAS Elyes <ehaouas@noos.fr> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
		
			
				
	
	
		
			421 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			421 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *
 | |
|  * 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.
 | |
|  */
 | |
| 
 | |
| #include <libpayload.h>
 | |
| #include <arch/cache.h>
 | |
| #include <assert.h>
 | |
| #include <endian.h>
 | |
| #include <queue.h>
 | |
| #include <stdio.h>
 | |
| #include <stdint.h>
 | |
| #include <stdlib.h>
 | |
| #include <usb/usb.h>
 | |
| 
 | |
| #include <udc/udc.h>
 | |
| 
 | |
| #ifdef DEBUG
 | |
| #define debug(x...) printf(x)
 | |
| #else
 | |
| #define debug(x...) do {} while (0)
 | |
| #endif
 | |
| 
 | |
| #define min(a, b) (((a) < (b)) ? (a) : (b))
 | |
| 
 | |
| static unsigned short strings_lang_id = 0;
 | |
| static unsigned char strings_count = 0;
 | |
| static const char **strings;
 | |
| 
 | |
| void udc_add_strings(unsigned short lang_id, unsigned char count,
 | |
| 	const char **str)
 | |
| {
 | |
| 	strings_lang_id = lang_id;
 | |
| 	strings_count = count;
 | |
| 	strings = str;
 | |
| }
 | |
| 
 | |
| /* determine if an additional zero length packet is necessary for
 | |
|  * a transfer */
 | |
| static unsigned int zlp(struct usbdev_ctrl *this, const int epnum,
 | |
| 	const int len, const int explen)
 | |
| {
 | |
| 	const unsigned int mps = this->ep_mps[epnum][1];
 | |
| 
 | |
| 	/* zero length transfers are handled explicitly */
 | |
| 	if (len == 0)
 | |
| 		return 0;
 | |
| 	/* host expects exactly the right amount, so no zlp necessary */
 | |
| 	if (len == explen)
 | |
| 		return 0;
 | |
| 	/* last packet will be short -> host knows that transfer is over */
 | |
| 	if ((len % mps) != 0)
 | |
| 		return 0;
 | |
| 
 | |
| 	/* otherwise we need an extra zero length packet */
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| static struct usbdev_configuration *fetch_config(struct usbdev_ctrl *this,
 | |
| 	int id)
 | |
| {
 | |
| 	struct usbdev_configuration *config;
 | |
| 	SLIST_FOREACH(config, &this->configs, list) {
 | |
| 		debug("checking descriptor %d\n",
 | |
| 			config->descriptor.bConfigurationValue);
 | |
| 		if (config->descriptor.bConfigurationValue == id)
 | |
| 			return config;
 | |
| 	}
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| static void cease_operation(struct usbdev_ctrl *this)
 | |
| {
 | |
| 	int i;
 | |
| 	for (i = 1; i < 16; i++) {
 | |
| 		/* disable endpoints */
 | |
| 		this->halt_ep(this, i, 0);
 | |
| 		this->halt_ep(this, i, 1);
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| static void enable_interface(struct usbdev_ctrl *this, int iface_num)
 | |
| {
 | |
| 	struct usbdev_configuration *config = this->current_config;
 | |
| 	struct usbdev_interface *iface = &config->interfaces[iface_num];
 | |
| 
 | |
| 	/* first: shut down all endpoints except EP0 */
 | |
| 	cease_operation(this);
 | |
| 
 | |
| 	/* now enable all configured endpoints */
 | |
| 	int epcount = iface->descriptor.bNumEndpoints;
 | |
| 	int i;
 | |
| 	for (i = 0; i < epcount; i++) {
 | |
| 		int ep = iface->eps[i].bEndpointAddress;
 | |
| 		int mps = iface->eps[i].wMaxPacketSize;
 | |
| 		int in_dir = 0;
 | |
| 		if (ep & 0x80) {
 | |
| 			in_dir = 1;
 | |
| 			ep &= 0x7f;
 | |
| 		}
 | |
| 		int ep_type = iface->eps[i].bmAttributes & 0x3;
 | |
| 		this->start_ep(this, ep, in_dir, ep_type, mps);
 | |
| 	}
 | |
| 
 | |
| 	this->current_iface = iface;
 | |
| 
 | |
| 	// gadget specific configuration
 | |
| 	if (iface->init)
 | |
| 		iface->init(this);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * handle default control transfers on EP 0
 | |
|  *
 | |
|  * returns 1 if transfer was handled
 | |
|  */
 | |
| static int setup_ep0(struct usbdev_ctrl *this, dev_req_t *dr)
 | |
| {
 | |
| 	if ((dr->bmRequestType == 0x00) &&
 | |
| 	    (dr->bRequest == SET_ADDRESS)) {
 | |
| 		this->set_address(this, dr->wValue & 0x7f);
 | |
| 
 | |
| 		/* status phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, NULL, 0, 0, 0);
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	if ((dr->bmRequestType == 0x00) &&
 | |
| 	    (dr->bRequest == SET_CONFIGURATION)) {
 | |
| 		struct usbdev_configuration *config =
 | |
| 			fetch_config(this, dr->wValue);
 | |
| 
 | |
| 		if (dr->wValue == 0)
 | |
| 			cease_operation(this);
 | |
| 
 | |
| 		if (config == NULL) {
 | |
| 			this->stall(this, 0, 0, 1);
 | |
| 			this->stall(this, 0, 1, 1);
 | |
| 			return 1;
 | |
| 		}
 | |
| 
 | |
| 		/* status phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, NULL, 0, 0, 0);
 | |
| 
 | |
| 		this->current_config = config;
 | |
| 		this->current_config_id = dr->wValue;
 | |
| 
 | |
| 		/* activate first interface */
 | |
| 		enable_interface(this, 0);
 | |
| 		this->initialized = 1;
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	if ((dr->bmRequestType == 0x80) &&
 | |
| 	    (dr->bRequest == GET_CONFIGURATION)) {
 | |
| 		unsigned char *res = dma_malloc(1);
 | |
| 		res[0] = this->current_config_id;
 | |
| 
 | |
| 		/* data phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, res, min(1, dr->wLength),
 | |
| 			0, 1);
 | |
| 
 | |
| 		/* status phase OUT */
 | |
| 		this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	// ENDPOINT_HALT
 | |
| 	if ((dr->bmRequestType == 0x02) && // endpoint
 | |
| 	    (dr->bRequest == CLEAR_FEATURE) &&
 | |
| 	    (dr->wValue == 0)) {
 | |
| 		int ep = dr->wIndex;
 | |
| 		/* clear STALL */
 | |
| 		this->stall(this, ep & 0xf, ep & 0x80, 0);
 | |
| 
 | |
| 		/* status phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, NULL, 0, 0, 0);
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	// ENDPOINT_HALT
 | |
| 	if ((dr->bmRequestType == 0x02) && // endpoint
 | |
| 	    (dr->bRequest == SET_FEATURE) &&
 | |
| 	    (dr->wValue == 0)) {
 | |
| 		int ep = dr->wIndex;
 | |
| 		/* set STALL */
 | |
| 		this->stall(this, ep & 0xf, ep & 0x80, 1);
 | |
| 
 | |
| 		/* status phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, NULL, 0, 0, 0);
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	// DEVICE_REMOTE_WAKEUP
 | |
| 	if ((dr->bmRequestType == 0x00) &&
 | |
| 	    (dr->bRequest == CLEAR_FEATURE) &&
 | |
| 	    (dr->wValue == 1)) {
 | |
| 		this->remote_wakeup = 0;
 | |
| 
 | |
| 		/* status phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, NULL, 0, 0, 0);
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	// DEVICE_REMOTE_WAKEUP
 | |
| 	if ((dr->bmRequestType == 0x00) &&
 | |
| 	    (dr->bRequest == SET_FEATURE) &&
 | |
| 	    (dr->wValue == 1)) {
 | |
| 		this->remote_wakeup = 1;
 | |
| 
 | |
| 		/* status phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, NULL, 0, 0, 0);
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	if ((dr->bmRequestType == 0x82) && // endpoint
 | |
| 	    (dr->bRequest == GET_STATUS)) {
 | |
| 		unsigned char *res = dma_malloc(2);
 | |
| 		int ep = dr->wIndex;
 | |
| 		/* is EP halted? */
 | |
| 		res[0] = this->ep_halted[ep & 0xf][(ep & 0x80) ? 1 : 0];
 | |
| 		res[1] = 0;
 | |
| 
 | |
| 		/* data phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, res,
 | |
| 			min(2, dr->wLength), 0, 1);
 | |
| 
 | |
| 		// status phase OUT
 | |
| 		this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	if ((dr->bmRequestType == 0x80) &&
 | |
| 	    (dr->bRequest == GET_STATUS)) {
 | |
| 		unsigned char *res = dma_malloc(2);
 | |
| 		res[0] = 1; // self powered
 | |
| 		if (this->remote_wakeup)
 | |
| 			res[0] |= 2;
 | |
| 
 | |
| 		res[1] = 0;
 | |
| 
 | |
| 		/* data phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, res,
 | |
| 			min(2, dr->wLength), 0, 1);
 | |
| 
 | |
| 		// status phase OUT
 | |
| 		this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	if ((dr->bmRequestType == 0x80) &&
 | |
| 	    (dr->bRequest == GET_DESCRIPTOR) &&
 | |
| 	    ((dr->wValue & 0xff00) == 0x0200)) {
 | |
| 		int i, j;
 | |
| 		/* config descriptor #id
 | |
| 		 * since config = 0 is undefined, but descriptors
 | |
| 		 * should start at 0, add 1 to have them match up.
 | |
| 		 */
 | |
| 		int id = (dr->wValue & 0xff) + 1;
 | |
| 		struct usbdev_configuration *config = fetch_config(this, id);
 | |
| 		if (config == NULL) {
 | |
| 			this->stall(this, 0, 0, 1);
 | |
| 			this->stall(this, 0, 1, 1);
 | |
| 			return 1;
 | |
| 		}
 | |
| 		debug("descriptor found, should be %d bytes\n",
 | |
| 			config->descriptor.wTotalLength);
 | |
| 
 | |
| 		uint8_t *data = dma_malloc(config->descriptor.wTotalLength);
 | |
| 		uint8_t *head = data;
 | |
| 
 | |
| 		memcpy(head, &config->descriptor,
 | |
| 			sizeof(configuration_descriptor_t));
 | |
| 		head += sizeof(configuration_descriptor_t);
 | |
| 
 | |
| 		for (i = 0; i < config->descriptor.bNumInterfaces; i++) {
 | |
| 			memcpy(head, &config->interfaces[i].descriptor,
 | |
| 				sizeof(interface_descriptor_t));
 | |
| 			head += sizeof(interface_descriptor_t);
 | |
| 			for (j = 0;
 | |
| 			     j < config->interfaces[i].descriptor.bNumEndpoints;
 | |
| 			     j++) {
 | |
| 				memcpy(head, &config->interfaces[i].eps[j],
 | |
| 					sizeof(endpoint_descriptor_t));
 | |
| 				head += sizeof(endpoint_descriptor_t);
 | |
| 			}
 | |
| 		}
 | |
| 		int size = config->descriptor.wTotalLength;
 | |
| 		assert((head - data) == config->descriptor.wTotalLength);
 | |
| 
 | |
| 		/* data phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, data,
 | |
| 			min(size, dr->wLength),
 | |
| 			zlp(this, 0, size, dr->wLength), 1);
 | |
| 
 | |
| 		/* status phase OUT */
 | |
| 		this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	if ((dr->bmRequestType == 0x80) &&
 | |
| 	    (dr->bRequest == GET_DESCRIPTOR) &&
 | |
| 	    ((dr->wValue & 0xff00) == 0x0300)) {
 | |
| 		int id = (dr->wValue & 0xff);
 | |
| 		if (id == 0) {
 | |
| 			if (strings_lang_id == 0)
 | |
| 				return 0;
 | |
| 
 | |
| 			uint8_t *data = dma_malloc(4);
 | |
| 			data[0] = 0x04; // length
 | |
| 			data[1] = 0x03; // string descriptor
 | |
| 			data[2] = strings_lang_id & 0xff;
 | |
| 			data[3] = strings_lang_id >> 8;
 | |
| 			/* data phase IN */
 | |
| 			this->enqueue_packet(this, 0, 1,
 | |
| 				data,
 | |
| 				min(data[0], dr->wLength),
 | |
| 				zlp(this, 0, data[0], dr->wLength),
 | |
| 				1);
 | |
| 
 | |
| 			/* status phase OUT */
 | |
| 			this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
 | |
| 		} else {
 | |
| 			if (strings_lang_id == 0)
 | |
| 				return 0;
 | |
| 
 | |
| 			int lang = dr->wIndex;
 | |
| 			if (lang != strings_lang_id)
 | |
| 				return 0;
 | |
| 
 | |
| 			if (id > strings_count)
 | |
| 				return 0;
 | |
| 
 | |
| 			int s_len = strlen(strings[id]);
 | |
| 			int d_len = s_len * 2;
 | |
| 
 | |
| 			uint8_t *data = dma_malloc(d_len + 2);
 | |
| 			memset(data, 0, d_len + 2);
 | |
| 			data[0] = d_len + 2; // length
 | |
| 			data[1] = 0x03; // string descriptor
 | |
| 			int i;
 | |
| 			for (i = 0; i < s_len; i++)
 | |
| 				data[i * 2 + 2] = strings[id][i];
 | |
| 
 | |
| 			/* data phase IN */
 | |
| 			this->enqueue_packet(this, 0, 1,
 | |
| 				data,
 | |
| 				min(d_len + 2, dr->wLength),
 | |
| 				zlp(this, 0, d_len + 2, dr->wLength),
 | |
| 				1);
 | |
| 
 | |
| 			/* status phase OUT */
 | |
| 			this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
 | |
| 		}
 | |
| 		return 1;
 | |
| 	} else
 | |
| 	if ((dr->bmRequestType == 0x80) &&
 | |
| 	    (dr->bRequest == GET_DESCRIPTOR) &&
 | |
| 	    ((dr->wValue & 0xff00) == 0x0100)) {
 | |
| 		device_descriptor_t *dd = dma_malloc(sizeof(*dd));
 | |
| 		memcpy(dd, &this->device_descriptor, sizeof(*dd));
 | |
| 		dd->bNumConfigurations = this->config_count;
 | |
| 
 | |
| 		/* data phase IN */
 | |
| 		this->enqueue_packet(this, 0, 1, (void *)dd,
 | |
| 			min(sizeof(*dd), dr->wLength),
 | |
| 			zlp(this, 0, sizeof(*dd), dr->wLength), 1);
 | |
| 
 | |
| 		/* status phase OUT */
 | |
| 		this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
 | |
| 		return 1;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| void udc_add_gadget(struct usbdev_ctrl *this,
 | |
| 	struct usbdev_configuration *config)
 | |
| {
 | |
| 	int i, size;
 | |
| 	SLIST_INSERT_HEAD(&this->configs, config, list);
 | |
| 
 | |
| 	size = sizeof(configuration_descriptor_t);
 | |
| 
 | |
| 	for (i = 0; i < config->descriptor.bNumInterfaces; i++) {
 | |
| 		size += sizeof(config->interfaces[i].descriptor);
 | |
| 		size += config->interfaces[i].descriptor.bNumEndpoints *
 | |
| 			sizeof(endpoint_descriptor_t);
 | |
| 	}
 | |
| 	config->descriptor.wTotalLength = size;
 | |
| 	config->descriptor.bConfigurationValue = ++this->config_count;
 | |
| }
 | |
| 
 | |
| void udc_handle_setup(struct usbdev_ctrl *this, int ep, dev_req_t *dr)
 | |
| {
 | |
| 	if ((ep == 0) && setup_ep0(this, dr))
 | |
| 		return;
 | |
| 
 | |
| 	if (this->current_config &&
 | |
| 	    this->current_config->interfaces[0].handle_setup &&
 | |
| 	    this->current_config->interfaces[0].handle_setup(this, ep, dr))
 | |
| 		return;
 | |
| 
 | |
| 	/* no successful SETUP transfer should end up here, report error */
 | |
| 	this->halt_ep(this, ep, 0);
 | |
| 	this->halt_ep(this, ep, 1);
 | |
| }
 |