Rename the generated config file to libpayload-config.h to differenciate it from other config.h files. Move the default location of the file to $(src)/include so that LIBPAYLOAD_PREFIX= users can access the file without staging it. Signed-off-by: Jordan Crouse <jordan@cosmicpenguin.net> Acked-by: Stefan Reinauer <stepan@coresystems.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3768 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
		
			
				
	
	
		
			380 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			380 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * This file is part of the libpayload project.
 | |
|  *
 | |
|  * Copyright (C) 2008 coresystems GmbH
 | |
|  *
 | |
|  * 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-config.h>
 | |
| #include <usb/usb.h>
 | |
| 
 | |
| hci_t *usb_hcs = 0;
 | |
| 
 | |
| hci_t *
 | |
| new_controller ()
 | |
| {
 | |
| 	hci_t *controller = malloc (sizeof (hci_t));
 | |
| 
 | |
| 	/* atomic */
 | |
| 	controller->next = usb_hcs;
 | |
| 	usb_hcs = controller;
 | |
| 	/* atomic end */
 | |
| 
 | |
| 	return controller;
 | |
| }
 | |
| 
 | |
| void
 | |
| detach_controller (hci_t *controller)
 | |
| {
 | |
| 	if (controller == 0)
 | |
| 		return;
 | |
| 	if (usb_hcs == controller) {
 | |
| 		usb_hcs = controller->next;
 | |
| 	} else {
 | |
| 		hci_t *it = usb_hcs;
 | |
| 		while (it != 0) {
 | |
| 			if (it->next == controller) {
 | |
| 				it->next = controller->next;
 | |
| 				return;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Polls all hubs on all USB controllers, to find out about device changes
 | |
|  */
 | |
| void
 | |
| usb_poll ()
 | |
| {
 | |
| 	if (usb_hcs == 0)
 | |
| 		return;
 | |
| 	hci_t *controller = usb_hcs;
 | |
| 	while (controller != 0) {
 | |
| 		int i;
 | |
| 		for (i = 0; i < 128; i++) {
 | |
| 			if (controller->devices[i] != 0) {
 | |
| 				controller->devices[i]->poll (controller->
 | |
| 							     devices[i]);
 | |
| 			}
 | |
| 		}
 | |
| 		controller = controller->next;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void
 | |
| init_device_entry (hci_t *controller, int i)
 | |
| {
 | |
| 	if (controller->devices[i] != 0)
 | |
| 		printf("warning: device %d reassigned?\n", i);
 | |
| 	controller->devices[i] = malloc(sizeof(usbdev_t));
 | |
| 	controller->devices[i]->controller = controller;
 | |
| 	controller->devices[i]->address = -1;
 | |
| 	controller->devices[i]->hub = -1;
 | |
| 	controller->devices[i]->port = -1;
 | |
| 	controller->devices[i]->init = usb_nop_init;
 | |
| 	controller->devices[i]->init (controller->devices[i]);
 | |
| }
 | |
| 
 | |
| void
 | |
| set_feature (usbdev_t *dev, int endp, int feature, int rtype)
 | |
| {
 | |
| 	dev_req_t dr;
 | |
| 
 | |
| 	dr.bmRequestType = rtype;
 | |
| 	dr.data_dir = host_to_device;
 | |
| 	dr.bRequest = SET_FEATURE;
 | |
| 	dr.wValue = feature;
 | |
| 	dr.wIndex = endp;
 | |
| 	dr.wLength = 0;
 | |
| 	dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
 | |
| }
 | |
| 
 | |
| void
 | |
| get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
 | |
| {
 | |
| 	dev_req_t dr;
 | |
| 
 | |
| 	dr.bmRequestType = rtype;
 | |
| 	dr.data_dir = device_to_host;
 | |
| 	dr.bRequest = GET_STATUS;
 | |
| 	dr.wValue = 0;
 | |
| 	dr.wIndex = intf;
 | |
| 	dr.wLength = len;
 | |
| 	dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
 | |
| }
 | |
| 
 | |
| u8 *
 | |
| get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
 | |
| 		int descIdx, int langID)
 | |
| {
 | |
| 	u8 buf[8];
 | |
| 	u8 *result;
 | |
| 	dev_req_t dr;
 | |
| 	int size;
 | |
| 
 | |
| 	dr.bmRequestType = bmRequestType;
 | |
| 	dr.data_dir = device_to_host;	// always like this for descriptors
 | |
| 	dr.bRequest = GET_DESCRIPTOR;
 | |
| 	dr.wValue = (descType << 8) | descIdx;
 | |
| 	dr.wIndex = langID;
 | |
| 	dr.wLength = 8;
 | |
| 	if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf)) {
 | |
| 		printf ("getting descriptor size (type %x) failed\n",
 | |
| 			descType);
 | |
| 	}
 | |
| 
 | |
| 	if (descType == 1) {
 | |
| 		device_descriptor_t *dd = (device_descriptor_t *) buf;
 | |
| 		printf ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
 | |
| 		if (dd->bMaxPacketSize0 != 0)
 | |
| 			dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
 | |
| 	}
 | |
| 
 | |
| 	/* special case for configuration descriptors: they carry all their
 | |
| 	   subsequent descriptors with them, and keep the entire size at a
 | |
| 	   different location */
 | |
| 	size = buf[0];
 | |
| 	if (buf[1] == 2) {
 | |
| 		int realsize = ((unsigned short *) (buf + 2))[0];
 | |
| 		size = realsize;
 | |
| 	}
 | |
| 	result = malloc (size);
 | |
| 	memset (result, 0, size);
 | |
| 	dr.wLength = size;
 | |
| 	if (dev->controller->
 | |
| 	    control (dev, IN, sizeof (dr), &dr, size, result)) {
 | |
| 		printf ("getting descriptor (type %x, size %x) failed\n",
 | |
| 			descType, size);
 | |
| 	}
 | |
| 
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| void
 | |
| set_configuration (usbdev_t *dev)
 | |
| {
 | |
| 	dev_req_t dr;
 | |
| 
 | |
| 	dr.bmRequestType = 0;
 | |
| 	dr.bRequest = SET_CONFIGURATION;
 | |
| 	dr.wValue = dev->configuration[5];
 | |
| 	dr.wIndex = 0;
 | |
| 	dr.wLength = 0;
 | |
| 	dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
 | |
| }
 | |
| 
 | |
| int
 | |
| clear_stall (endpoint_t *ep)
 | |
| {
 | |
| 	usbdev_t *dev = ep->dev;
 | |
| 	int endp = ep->endpoint;
 | |
| 	dev_req_t dr;
 | |
| 
 | |
| 	dr.bmRequestType = 0;
 | |
| 	if (endp != 0) {
 | |
| 		dr.req_recp = endp_recp;
 | |
| 	}
 | |
| 	dr.bRequest = CLEAR_FEATURE;
 | |
| 	dr.wValue = ENDPOINT_HALT;
 | |
| 	dr.wIndex = endp;
 | |
| 	dr.wLength = 0;
 | |
| 	dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* returns free address or -1 */
 | |
| static int
 | |
| get_free_address (hci_t *controller)
 | |
| {
 | |
| 	int i;
 | |
| 	for (i = 1; i < 128; i++) {
 | |
| 		if (controller->devices[i] == 0)
 | |
| 			return i;
 | |
| 	}
 | |
| 	printf ("no free address found\n");
 | |
| 	return -1;		// no free address
 | |
| }
 | |
| 
 | |
| int
 | |
| set_address (hci_t *controller, int lowspeed)
 | |
| {
 | |
| 	int adr = get_free_address (controller);	// address to set
 | |
| 	dev_req_t dr;
 | |
| 	configuration_descriptor_t *cd;
 | |
| 	device_descriptor_t *dd;
 | |
| 
 | |
| 	memset (&dr, 0, sizeof (dr));
 | |
| 	dr.data_dir = host_to_device;
 | |
| 	dr.req_type = standard_type;
 | |
| 	dr.req_recp = dev_recp;
 | |
| 	dr.bRequest = SET_ADDRESS;
 | |
| 	dr.wValue = adr;
 | |
| 	dr.wIndex = 0;
 | |
| 	dr.wLength = 0;
 | |
| 
 | |
| 	init_device_entry(controller, adr);
 | |
| 	usbdev_t *dev = controller->devices[adr];
 | |
| 	// dummy values for registering the address
 | |
| 	dev->address = 0;
 | |
| 	dev->lowspeed = lowspeed;
 | |
| 	dev->endpoints[0].dev = dev;
 | |
| 	dev->endpoints[0].endpoint = 0;
 | |
| 	dev->endpoints[0].maxpacketsize = 8;
 | |
| 	dev->endpoints[0].toggle = 0;
 | |
| 	dev->endpoints[0].direction = SETUP;
 | |
| 	mdelay (50);
 | |
| 	if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0)) {
 | |
| 		printf ("set_address failed\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 	mdelay (50);
 | |
| 	dev->address = adr;
 | |
| 	dev->descriptor =
 | |
| 		get_descriptor (dev,
 | |
| 				gen_bmRequestType (device_to_host,
 | |
| 						   standard_type, dev_recp),
 | |
| 				1, 0, 0);
 | |
| 	dd = (device_descriptor_t *) dev->descriptor;
 | |
| 	printf ("device version: %x.%x\n", dd->bcdUSB >> 8,
 | |
| 		dd->bcdUSB & 0xff);
 | |
| 	printf ("device has %x configurations\n", dd->bNumConfigurations);
 | |
| 	if (dd->bNumConfigurations == 0) {
 | |
| 		/* device isn't usable */
 | |
| 		printf ("no usable configuration!\n");
 | |
| 		dev->address = 0;
 | |
| 		return -1;
 | |
| 	}
 | |
| 	dev->configuration =
 | |
| 		get_descriptor (dev,
 | |
| 				gen_bmRequestType (device_to_host,
 | |
| 						   standard_type, dev_recp),
 | |
| 				2, 0, 0);
 | |
| 	cd = (configuration_descriptor_t *) dev->configuration;
 | |
| 	set_configuration (dev);
 | |
| 	interface_descriptor_t *interface =
 | |
| 		(interface_descriptor_t *) (((char *) cd) + cd->bLength);
 | |
| 	{
 | |
| 		int i;
 | |
| 		int num = cd->bNumInterfaces;
 | |
| 		interface_descriptor_t *current = interface;
 | |
| 		printf ("device has %x interfaces\n", num);
 | |
| 		num = (num > 5) ? 5 : num;
 | |
| 		for (i = 0; i < num; i++) {
 | |
| 			int j;
 | |
| 			printf (" #%x has %x endpoints, interface %x:%x, protocol %x\n", current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
 | |
| 			endpoint_descriptor_t *endp =
 | |
| 				(endpoint_descriptor_t *) (((char *) current)
 | |
| 							   +
 | |
| 							   current->bLength);
 | |
| 			if (interface->bInterfaceClass == 0x3)
 | |
| 				endp = (endpoint_descriptor_t *) (((char *) endp) + ((char *) endp)[0]);	// ignore HID descriptor
 | |
| 			memset (dev->endpoints, 0, sizeof (dev->endpoints));
 | |
| 			dev->num_endp = 1;	// 0 always exists
 | |
| 			dev->endpoints[0].dev = dev;
 | |
| 			dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
 | |
| 			dev->endpoints[0].direction = SETUP;
 | |
| 			dev->endpoints[0].type = CONTROL;
 | |
| 			for (j = 1; j <= current->bNumEndpoints; j++) {
 | |
| 				static const char *transfertypes[4] =
 | |
| 					{ "control", "isochronous", "bulk",
 | |
| 					"interrupt"
 | |
| 				};
 | |
| 				printf ("   #%x: Endpoint %x (%s), max packet size %x, type %s\n", j, endp->bEndpointAddress & 0x7f, ((endp->bEndpointAddress & 0x80) != 0) ? "in" : "out", endp->wMaxPacketSize, transfertypes[endp->bmAttributes]);
 | |
| 				endpoint_t *ep =
 | |
| 					&dev->endpoints[dev->num_endp++];
 | |
| 				ep->dev = dev;
 | |
| 				ep->endpoint = endp->bEndpointAddress;
 | |
| 				ep->toggle = 0;
 | |
| 				ep->maxpacketsize = endp->wMaxPacketSize;
 | |
| 				ep->direction =
 | |
| 					((endp->bEndpointAddress & 0x80) ==
 | |
| 					 0) ? OUT : IN;
 | |
| 				ep->type = endp->bmAttributes;
 | |
| 				endp = (endpoint_descriptor_t
 | |
| 					*) (((char *) endp) + endp->bLength);
 | |
| 			}
 | |
| 			current = (interface_descriptor_t *) endp;
 | |
| 		}
 | |
| 	}
 | |
| 	int class = dd->bDeviceClass;
 | |
| 	if (class == 0)
 | |
| 		class = interface->bInterfaceClass;
 | |
| 
 | |
| 	enum { hid_device = 0x3, msc_device = 0x8, hub_device = 0x9 };
 | |
| 
 | |
| 	printf ("device of class %x found\n", class);
 | |
| 	if (class == hub_device) {
 | |
| 		printf ("hub found\n");
 | |
| #ifdef CONFIG_USB_HUB
 | |
| 		controller->devices[adr]->init = usb_hub_init;
 | |
| #else
 | |
| 		printf ("support not compiled in\n");
 | |
| #endif
 | |
| 	}
 | |
| 	if (class == hid_device) {
 | |
| 		printf ("HID found\n");
 | |
| #ifdef CONFIG_USB_HID
 | |
| 		controller->devices[adr]->init = usb_hid_init;
 | |
| #else
 | |
| 		printf ("support not compiled in\n");
 | |
| #endif
 | |
| 	}
 | |
| 	if (class == msc_device) {
 | |
| 		printf ("MSC found\n");
 | |
| #ifdef CONFIG_USB_MSC
 | |
| 		controller->devices[adr]->init = usb_msc_init;
 | |
| #else
 | |
| 		printf ("support not compiled in\n");
 | |
| #endif
 | |
| 	}
 | |
| 	return adr;
 | |
| }
 | |
| 
 | |
| void
 | |
| usb_detach_device(hci_t *controller, int devno)
 | |
| {
 | |
| 	controller->devices[devno]->destroy (controller->devices[devno]);
 | |
| 	free(controller->devices[devno]);
 | |
| 	controller->devices[devno] = 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| usb_attach_device(hci_t *controller, int hubaddress, int port, int lowspeed)
 | |
| {
 | |
| 	printf ("%sspeed device\n", (lowspeed == 1) ? "low" : "full");
 | |
| 	int newdev = set_address (controller, lowspeed);
 | |
| 	if (newdev == -1)
 | |
| 		return -1;
 | |
| 	usbdev_t *newdev_t = controller->devices[newdev];
 | |
| 
 | |
| 	newdev_t->address = newdev;
 | |
| 	newdev_t->hub = hubaddress;
 | |
| 	newdev_t->port = port;
 | |
| 	// determine responsible driver - current done in set_address
 | |
| 	newdev_t->init (newdev_t);
 | |
| 	return newdev;
 | |
| }
 |