usb:Adding usb enumeration.
usbd update from JPEmbedded Change-Id: I4098b29a3188abe7110d59f0746ea40ac5818bbf http://gerrit.minix3.org/#/c/2698/
This commit is contained in:
		
							parent
							
								
									146e5a99e4
								
							
						
					
					
						commit
						880ae44a72
					
				@ -5,6 +5,8 @@
 | 
			
		||||
#include <ddekit/ddekit.h>		/* ddekit_init */
 | 
			
		||||
#include <ddekit/thread.h>		/* DDEKit threading */
 | 
			
		||||
 | 
			
		||||
#include <libdde/usb_server.h>		/* DDEKit USB server */
 | 
			
		||||
 | 
			
		||||
#include <minix/devman.h>		/* Initializing 'devman' */
 | 
			
		||||
#include <minix/sef.h>			/* SEF handling */
 | 
			
		||||
 | 
			
		||||
@ -22,7 +24,6 @@ static void usbd_server_thread(void *);
 | 
			
		||||
 | 
			
		||||
/* TODO: No headers for these... */
 | 
			
		||||
extern void ddekit_minix_wait_exit(void); /* dde.c */
 | 
			
		||||
extern void ddekit_usb_server_init(void); /* usb_server.c */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
@ -34,6 +35,7 @@ main(int UNUSED(argc), char * UNUSED(argv[]))
 | 
			
		||||
	int ret_val;
 | 
			
		||||
 | 
			
		||||
	USB_MSG("Starting USBD");
 | 
			
		||||
	USB_DBG("Built: %s %s", __DATE__, __TIME__);
 | 
			
		||||
 | 
			
		||||
	/* Basic SEF,DDE,... initialization */
 | 
			
		||||
	usbd_init();
 | 
			
		||||
 | 
			
		||||
@ -2,9 +2,11 @@
 | 
			
		||||
 * Implementation of generic HCD
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <time.h>				/* nanosleep */
 | 
			
		||||
#include <string.h>				/* memcpy */
 | 
			
		||||
 | 
			
		||||
#include <minix/drivers.h>			/* errno with sign */
 | 
			
		||||
#include <minix/usb.h>				/* USB_TRANSFER_CTL...  */
 | 
			
		||||
 | 
			
		||||
#include <usb/hcd_common.h>
 | 
			
		||||
#include <usb/hcd_ddekit.h>
 | 
			
		||||
#include <usb/hcd_interface.h>
 | 
			
		||||
@ -27,15 +29,21 @@ static int hcd_set_address(hcd_device_state *, int);
 | 
			
		||||
static int hcd_get_descriptor_tree(hcd_device_state *);
 | 
			
		||||
static int hcd_set_configuration(hcd_device_state *, int);
 | 
			
		||||
static int hcd_handle_urb(hcd_device_state *);
 | 
			
		||||
static int hcd_control_urb(hcd_device_state *);
 | 
			
		||||
static int hcd_bulk_urb(hcd_device_state *);
 | 
			
		||||
 | 
			
		||||
/* For internal use by more general methods */
 | 
			
		||||
static int hcd_setup_packet(hcd_device_state *, hcd_ctrlrequest *);
 | 
			
		||||
static int hcd_bulk_transfer(hcd_device_state *, hcd_bulkrequest *, int);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    Local definitions                                                      *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
/* TODO: Only one device at a time */
 | 
			
		||||
/* TODO: Only one device at a time
 | 
			
		||||
 * If ever HUB functionality is added, one must remember that disconnecting
 | 
			
		||||
 * HUB, means disconnecting every device attached to it, so data structure may
 | 
			
		||||
 * have to be altered to allow that */
 | 
			
		||||
static hcd_device_state hcd_device[1];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -55,13 +63,13 @@ hcd_handle_event(hcd_driver_state * driver)
 | 
			
		||||
	/* Sometimes interrupts occur in a weird order (EP after disconnect)
 | 
			
		||||
	 * This helps finding ordering errors in DEBUG */
 | 
			
		||||
	USB_DBG("Event: 0x%02X, state: 0x%02X",
 | 
			
		||||
		driver->event, this_device->state);
 | 
			
		||||
		driver->current_event, this_device->state);
 | 
			
		||||
 | 
			
		||||
	/* Set what was received for device thread to use */
 | 
			
		||||
	this_device->driver = driver;
 | 
			
		||||
 | 
			
		||||
	/* Handle event and forward control to device thread when required */
 | 
			
		||||
	switch (driver->event) {
 | 
			
		||||
	switch (driver->current_event) {
 | 
			
		||||
		case HCD_EVENT_CONNECTED:
 | 
			
		||||
			if (HCD_STATE_DISCONNECTED == this_device->state) {
 | 
			
		||||
				if (EXIT_SUCCESS != hcd_connect_device(
 | 
			
		||||
@ -89,6 +97,7 @@ hcd_handle_event(hcd_driver_state * driver)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case HCD_EVENT_ENDPOINT:
 | 
			
		||||
		case HCD_EVENT_URB:
 | 
			
		||||
			/* Allow device thread to continue with it's logic */
 | 
			
		||||
			if (HCD_STATE_DISCONNECTED != this_device->state)
 | 
			
		||||
				hcd_device_continue(this_device);
 | 
			
		||||
@ -133,13 +142,13 @@ hcd_device_thread(void * thread_args)
 | 
			
		||||
 | 
			
		||||
	USB_DBG("Waiting for URBs");
 | 
			
		||||
 | 
			
		||||
	/* No URB's yet */
 | 
			
		||||
	this_device->urb = NULL;
 | 
			
		||||
 | 
			
		||||
	/* Start handling URB's */
 | 
			
		||||
	for(;;) {
 | 
			
		||||
		/* No URB's yet */
 | 
			
		||||
		this_device->urb = NULL;
 | 
			
		||||
 | 
			
		||||
		/* Block and wait for something like 'submit URB' */
 | 
			
		||||
		hcd_device_wait(this_device);
 | 
			
		||||
		hcd_device_wait(this_device, HCD_EVENT_URB, HCD_NO_ENDPOINT);
 | 
			
		||||
 | 
			
		||||
		if (EXIT_SUCCESS != hcd_handle_urb(this_device))
 | 
			
		||||
			hcd_device_finish(this_device, "URB handling failed");
 | 
			
		||||
@ -162,7 +171,7 @@ hcd_device_finish(hcd_device_state * this_device, const char * finish_msg)
 | 
			
		||||
 | 
			
		||||
	/* Lock forever */
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		hcd_device_wait(this_device);
 | 
			
		||||
		hcd_device_wait(this_device, HCD_EVENT_URB, HCD_NO_ENDPOINT);
 | 
			
		||||
		USB_MSG("Failed attempt to continue finished thread");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -181,10 +190,11 @@ hcd_enumerate(hcd_device_state * this_device)
 | 
			
		||||
	d = this_device->driver;
 | 
			
		||||
 | 
			
		||||
	/* First let driver reset device */
 | 
			
		||||
	d->reset_device(d->private_data);
 | 
			
		||||
 | 
			
		||||
	/* Set parameters for further communication */
 | 
			
		||||
	d->setup_device(d->private_data, HCD_DEFAULT_EP, HCD_DEFAULT_ADDR);
 | 
			
		||||
	if (EXIT_SUCCESS != d->reset_device(d->private_data,
 | 
			
		||||
					&(this_device->speed))) {
 | 
			
		||||
		USB_MSG("Failed to reset device");
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Get device descriptor */
 | 
			
		||||
	if (EXIT_SUCCESS != hcd_get_device_descriptor(this_device)) {
 | 
			
		||||
@ -201,7 +211,7 @@ hcd_enumerate(hcd_device_state * this_device)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set parameters for further communication */
 | 
			
		||||
	d->setup_device(d->private_data, HCD_DEFAULT_EP, HCD_ATTACHED_ADDR);
 | 
			
		||||
	d->setup_device(d->private_data, HCD_DEFAULT_EP, this_device->address);
 | 
			
		||||
 | 
			
		||||
	/* Get other descriptors */
 | 
			
		||||
	if (EXIT_SUCCESS != hcd_get_descriptor_tree(this_device)) {
 | 
			
		||||
@ -254,11 +264,29 @@ hcd_get_device_descriptor(hcd_device_state * this_device)
 | 
			
		||||
	/* Remember max packet size from device descriptor */
 | 
			
		||||
	this_device->max_packet_size = this_device->device_desc.bMaxPacketSize;
 | 
			
		||||
 | 
			
		||||
	/* Output VID/PID when debugging */
 | 
			
		||||
	USB_DBG("idVendor: %02X%02X", this_device->device_desc.idVendor[1],
 | 
			
		||||
					this_device->device_desc.idVendor[0]);
 | 
			
		||||
	USB_DBG("idProduct: %02X%02X", this_device->device_desc.idProduct[1],
 | 
			
		||||
					this_device->device_desc.idProduct[0]);
 | 
			
		||||
	/* Dump device descriptor in debug mode */
 | 
			
		||||
#ifdef DEBUG
 | 
			
		||||
	{
 | 
			
		||||
		hcd_device_descriptor * d;
 | 
			
		||||
		d = &(this_device->device_desc);
 | 
			
		||||
 | 
			
		||||
		USB_DBG("<<DEVICE>>");
 | 
			
		||||
		USB_DBG("bLength %02X",			d->bLength);
 | 
			
		||||
		USB_DBG("bDescriptorType %02X",		d->bDescriptorType);
 | 
			
		||||
		USB_DBG("bcdUSB %04X",			UGETW(d->bcdUSB));
 | 
			
		||||
		USB_DBG("bDeviceClass %02X",		d->bDeviceClass);
 | 
			
		||||
		USB_DBG("bDeviceSubClass %02X",		d->bDeviceSubClass);
 | 
			
		||||
		USB_DBG("bDeviceProtocol %02X",		d->bDeviceProtocol);
 | 
			
		||||
		USB_DBG("bMaxPacketSize %02X",		d->bMaxPacketSize);
 | 
			
		||||
		USB_DBG("idVendor %04X",		UGETW(d->idVendor));
 | 
			
		||||
		USB_DBG("idProduct %04X",		UGETW(d->idProduct));
 | 
			
		||||
		USB_DBG("bcdDevice %04X",		UGETW(d->bcdDevice));
 | 
			
		||||
		USB_DBG("iManufacturer %02X",		d->iManufacturer);
 | 
			
		||||
		USB_DBG("iProduct %02X",		d->iProduct);
 | 
			
		||||
		USB_DBG("iSerialNumber %02X",		d->iSerialNumber);
 | 
			
		||||
		USB_DBG("bNumConfigurations %02X",	d->bNumConfigurations);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@ -289,11 +317,11 @@ hcd_set_address(hcd_device_state * this_device, int address)
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		/* Sleep 5ms for proper addressing */
 | 
			
		||||
		struct timespec nanotm = {0, HCD_NANOSLEEP_MSEC(5)};
 | 
			
		||||
		nanosleep(&nanotm, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	/* Sleep 5msec to allow addressing */
 | 
			
		||||
	hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(5));
 | 
			
		||||
 | 
			
		||||
	/* Remember what was assigned in hardware */
 | 
			
		||||
	this_device->address = address;
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@ -412,15 +440,180 @@ hcd_set_configuration(hcd_device_state * this_device, int configuration)
 | 
			
		||||
static int
 | 
			
		||||
hcd_handle_urb(hcd_device_state * this_device)
 | 
			
		||||
{
 | 
			
		||||
	hcd_urb * urb;
 | 
			
		||||
	int transfer_status;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	USB_ASSERT(NULL != this_device->urb, "NULL URB received");
 | 
			
		||||
	transfer_status = EXIT_FAILURE;
 | 
			
		||||
	urb = this_device->urb;
 | 
			
		||||
 | 
			
		||||
	/* TODO: URB handling will be here */
 | 
			
		||||
	USB_ASSERT(NULL != urb, "NULL URB given");
 | 
			
		||||
	/* TODO: One device only */
 | 
			
		||||
	USB_ASSERT((void *)this_device != (void *)urb->dev,
 | 
			
		||||
		"Unknown device for URB");
 | 
			
		||||
 | 
			
		||||
	/* TODO: call completion */
 | 
			
		||||
	/* hcd_completion_cb */
 | 
			
		||||
	switch (urb->type) {
 | 
			
		||||
 | 
			
		||||
		case USB_TRANSFER_CTL:
 | 
			
		||||
			transfer_status = hcd_control_urb(this_device);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case USB_TRANSFER_BLK:
 | 
			
		||||
			transfer_status = hcd_bulk_urb(this_device);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case USB_TRANSFER_INT:
 | 
			
		||||
			/* TODO: transfer */
 | 
			
		||||
			USB_MSG("Interrupt transfer not supported");
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case USB_TRANSFER_ISO:
 | 
			
		||||
			/* TODO: transfer */
 | 
			
		||||
			USB_MSG("ISO transfer not supported");
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			USB_MSG("Invalid transfer type 0x%X", urb->type);
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifndef URB_TEST
 | 
			
		||||
	/* Call completion */
 | 
			
		||||
	hcd_completion_cb(urb->priv);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* Only critical failures should ever yield EXIT_FAILURE */
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    hcd_control_urb                                                        *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static int
 | 
			
		||||
hcd_control_urb(hcd_device_state * this_device)
 | 
			
		||||
{
 | 
			
		||||
	hcd_urb * urb;
 | 
			
		||||
	hcd_ctrlrequest setup;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	urb = this_device->urb;
 | 
			
		||||
 | 
			
		||||
	/* Assume bad values unless something different occurs later */
 | 
			
		||||
	urb->status = EINVAL;
 | 
			
		||||
 | 
			
		||||
	/* Must have setup packet */
 | 
			
		||||
	if (NULL == urb->setup_packet) {
 | 
			
		||||
		USB_MSG("No setup packet in URB, for control transfer");
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* TODO: Only EP0 can have control transfer */
 | 
			
		||||
	if (0 != urb->endpoint) {
 | 
			
		||||
		USB_MSG("Control transfer for non zero EP");
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Hold setup packet and analyze it */
 | 
			
		||||
	memcpy(&setup, urb->setup_packet, sizeof(setup));
 | 
			
		||||
 | 
			
		||||
	/* TODO: broken constants for urb->direction (USB_OUT...) */
 | 
			
		||||
	if (((setup.bRequestType >> 7) & 0x01) != urb->direction) {
 | 
			
		||||
		USB_MSG("URB Direction mismatch");
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Send setup packet */
 | 
			
		||||
	if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup)) {
 | 
			
		||||
		USB_MSG("Sending URB setup packet, failed");
 | 
			
		||||
		urb->status = EPIPE;
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	urb->status = EXIT_SUCCESS;
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    hcd_bulk_urb                                                           *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static int
 | 
			
		||||
hcd_bulk_urb(hcd_device_state * this_device)
 | 
			
		||||
{
 | 
			
		||||
	hcd_endpoint * e;
 | 
			
		||||
	hcd_bulkrequest request;
 | 
			
		||||
	hcd_urb * urb;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	urb = this_device->urb;
 | 
			
		||||
 | 
			
		||||
	/* Assume bad values unless something different occurs later */
 | 
			
		||||
	urb->status = EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (NULL == urb->data) {
 | 
			
		||||
		USB_MSG("No data packet in URB, for bulk transfer");
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((UE_GET_ADDR(urb->endpoint) >= 16) ||
 | 
			
		||||
		(UE_GET_ADDR(urb->endpoint) <= 0)) {
 | 
			
		||||
		USB_MSG("Illegal EP number");
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* TODO: broken USB_IN... constants */
 | 
			
		||||
	if ((1 != urb->direction) && (0 != urb->direction)) {
 | 
			
		||||
		USB_MSG("Illegal EP direction");
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* TODO: Any additional checks? (sane size?) */
 | 
			
		||||
 | 
			
		||||
	/* Assign to bulk request structure */
 | 
			
		||||
	request.endpoint = urb->endpoint;
 | 
			
		||||
	request.size = (int)urb->size;
 | 
			
		||||
	request.data = urb->data;
 | 
			
		||||
 | 
			
		||||
	/* Check if EP number is valid */
 | 
			
		||||
	e = hcd_tree_find_ep(&(this_device->config_tree), request.endpoint);
 | 
			
		||||
 | 
			
		||||
	if (NULL == e) {
 | 
			
		||||
		USB_MSG("Invalid EP value");
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* TODO: broken constants for urb->direction (USB_OUT...) */
 | 
			
		||||
	/* Check if remembered direction matches */
 | 
			
		||||
	if (((e->descriptor.bEndpointAddress >> 7) & 0x01) != urb->direction) {
 | 
			
		||||
		USB_MSG("EP direction mismatch");
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check if remembered type matches */
 | 
			
		||||
	if (e->descriptor.bmAttributes != UE_BULK) {
 | 
			
		||||
		USB_MSG("EP type mismatch");
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Assign to let know how much data can be transfered at a time */
 | 
			
		||||
	request.max_packet_size = UGETW(e->descriptor.wMaxPacketSize);
 | 
			
		||||
 | 
			
		||||
	/* Let know how to configure EP for speed */
 | 
			
		||||
	request.speed = this_device->speed;
 | 
			
		||||
 | 
			
		||||
	/* Send bulk data */
 | 
			
		||||
	if (EXIT_SUCCESS != hcd_bulk_transfer(this_device, &request,
 | 
			
		||||
						urb->direction)) {
 | 
			
		||||
		USB_MSG("URB bulk transfer, failed");
 | 
			
		||||
		urb->status = EPIPE;
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	urb->status = EXIT_SUCCESS;
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -447,10 +640,12 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup)
 | 
			
		||||
	d->setup_stage(d->private_data, setup);
 | 
			
		||||
 | 
			
		||||
	/* Wait for response */
 | 
			
		||||
	hcd_device_wait(this_device);
 | 
			
		||||
	hcd_device_wait(this_device, HCD_EVENT_ENDPOINT, HCD_ENDPOINT_0);
 | 
			
		||||
 | 
			
		||||
	/* Check response */
 | 
			
		||||
	if (EXIT_SUCCESS != d->check_error(d->private_data))
 | 
			
		||||
	if (EXIT_SUCCESS != d->check_error(d->private_data,
 | 
			
		||||
					HCD_TRANSFER_CONTROL,
 | 
			
		||||
					HCD_DIRECTION_UNUSED))
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
 | 
			
		||||
	/* For data packets... */
 | 
			
		||||
@ -468,11 +663,15 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup)
 | 
			
		||||
				d->in_data_stage(d->private_data);
 | 
			
		||||
 | 
			
		||||
				/* Wait for response */
 | 
			
		||||
				hcd_device_wait(this_device);
 | 
			
		||||
				hcd_device_wait(this_device,
 | 
			
		||||
						HCD_EVENT_ENDPOINT,
 | 
			
		||||
						HCD_ENDPOINT_0);
 | 
			
		||||
 | 
			
		||||
				/* Check response */
 | 
			
		||||
				if (EXIT_SUCCESS != d->check_error(
 | 
			
		||||
							d->private_data))
 | 
			
		||||
							d->private_data,
 | 
			
		||||
							HCD_TRANSFER_CONTROL,
 | 
			
		||||
							HCD_DIRECTION_UNUSED))
 | 
			
		||||
					return EXIT_FAILURE;
 | 
			
		||||
 | 
			
		||||
				/* Read data received as response */
 | 
			
		||||
@ -510,10 +709,13 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup)
 | 
			
		||||
		d->out_status_stage(d->private_data);
 | 
			
		||||
 | 
			
		||||
		/* Wait for response */
 | 
			
		||||
		hcd_device_wait(this_device);
 | 
			
		||||
		hcd_device_wait(this_device, HCD_EVENT_ENDPOINT,
 | 
			
		||||
				HCD_ENDPOINT_0);
 | 
			
		||||
 | 
			
		||||
		/* Check response */
 | 
			
		||||
		if (EXIT_SUCCESS != d->check_error(d->private_data))
 | 
			
		||||
		if (EXIT_SUCCESS != d->check_error(d->private_data,
 | 
			
		||||
						HCD_TRANSFER_CONTROL,
 | 
			
		||||
						HCD_DIRECTION_UNUSED))
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
@ -522,10 +724,13 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup)
 | 
			
		||||
		d->in_status_stage(d->private_data);
 | 
			
		||||
 | 
			
		||||
		/* Wait for response */
 | 
			
		||||
		hcd_device_wait(this_device);
 | 
			
		||||
		hcd_device_wait(this_device, HCD_EVENT_ENDPOINT,
 | 
			
		||||
				HCD_ENDPOINT_0);
 | 
			
		||||
 | 
			
		||||
		/* Check response */
 | 
			
		||||
		if (EXIT_SUCCESS != d->check_error(d->private_data))
 | 
			
		||||
		if (EXIT_SUCCESS != d->check_error(d->private_data,
 | 
			
		||||
						HCD_TRANSFER_CONTROL,
 | 
			
		||||
						HCD_DIRECTION_UNUSED))
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
 | 
			
		||||
		/* Read zero data from response to clear registers */
 | 
			
		||||
@ -535,3 +740,103 @@ hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup)
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    hcd_bulk_transfer                                                      *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static int
 | 
			
		||||
hcd_bulk_transfer(hcd_device_state * this_device, hcd_bulkrequest * request,
 | 
			
		||||
		int direction)
 | 
			
		||||
{
 | 
			
		||||
	hcd_driver_state * d;
 | 
			
		||||
	hcd_bulkrequest temp_req;
 | 
			
		||||
	int transfer_len;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	/* Initially... */
 | 
			
		||||
	d = this_device->driver;
 | 
			
		||||
 | 
			
		||||
	/* Set parameters for further communication */
 | 
			
		||||
	d->setup_device(d->private_data,
 | 
			
		||||
			request->endpoint,
 | 
			
		||||
			this_device->address);
 | 
			
		||||
 | 
			
		||||
	/* TODO: broken USB_IN... constants */
 | 
			
		||||
	if (1 == direction) {
 | 
			
		||||
 | 
			
		||||
		do {
 | 
			
		||||
			/* Start actual bulk transfer */
 | 
			
		||||
			d->bulk_in_stage(d->private_data, request);
 | 
			
		||||
 | 
			
		||||
			/* Wait for response */
 | 
			
		||||
			hcd_device_wait(this_device, HCD_EVENT_ENDPOINT,
 | 
			
		||||
					request->endpoint);
 | 
			
		||||
 | 
			
		||||
			/* Check response */
 | 
			
		||||
			if (EXIT_SUCCESS != d->check_error(d->private_data,
 | 
			
		||||
							HCD_TRANSFER_BULK,
 | 
			
		||||
							HCD_DIRECTION_IN))
 | 
			
		||||
				return EXIT_FAILURE;
 | 
			
		||||
 | 
			
		||||
			/* Read data received as response */
 | 
			
		||||
			transfer_len = d->read_data(d->private_data,
 | 
			
		||||
						(hcd_reg1 *)request->data,
 | 
			
		||||
						request->endpoint);
 | 
			
		||||
 | 
			
		||||
			request->size -= transfer_len;
 | 
			
		||||
			request->data += transfer_len;
 | 
			
		||||
 | 
			
		||||
			/* Total length shall not become negative */
 | 
			
		||||
			USB_ASSERT(request->size >= 0,
 | 
			
		||||
				"Invalid amount of data received");
 | 
			
		||||
 | 
			
		||||
			/* TODO: REMOVEME (dumping of bulk transfer) */
 | 
			
		||||
			{
 | 
			
		||||
				int i;
 | 
			
		||||
				USB_MSG("RECEIVED: %d", transfer_len);
 | 
			
		||||
				for (i = 0; i < transfer_len; i++)
 | 
			
		||||
					USB_MSG("%c",
 | 
			
		||||
					(request->data-transfer_len)[i]);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		} while (0 != request->size);
 | 
			
		||||
 | 
			
		||||
	} else if (0 == direction) {
 | 
			
		||||
 | 
			
		||||
		do {
 | 
			
		||||
			temp_req = *request;
 | 
			
		||||
 | 
			
		||||
			/* Decide transfer size */
 | 
			
		||||
			if (temp_req.size > (int)temp_req.max_packet_size) {
 | 
			
		||||
				temp_req.size = temp_req.max_packet_size;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			request->data += temp_req.size;
 | 
			
		||||
			request->size -= temp_req.size;
 | 
			
		||||
 | 
			
		||||
			/* Total length shall not become negative */
 | 
			
		||||
			USB_ASSERT(request->size >= 0,
 | 
			
		||||
				"Invalid amount of data received");
 | 
			
		||||
 | 
			
		||||
			/* Start actual bulk transfer */
 | 
			
		||||
			d->bulk_out_stage(d->private_data, &temp_req);
 | 
			
		||||
 | 
			
		||||
			/* Wait for response */
 | 
			
		||||
			hcd_device_wait(this_device, HCD_EVENT_ENDPOINT,
 | 
			
		||||
					request->endpoint);
 | 
			
		||||
 | 
			
		||||
			/* Check response */
 | 
			
		||||
			if (EXIT_SUCCESS != d->check_error(d->private_data,
 | 
			
		||||
							HCD_TRANSFER_BULK,
 | 
			
		||||
							HCD_DIRECTION_OUT))
 | 
			
		||||
				return EXIT_FAILURE;
 | 
			
		||||
 | 
			
		||||
		} while (0 != request->size);
 | 
			
		||||
 | 
			
		||||
	} else
 | 
			
		||||
		USB_ASSERT(0, "Invalid transfer direction");
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>			/* memset... */
 | 
			
		||||
#include <time.h>			/* nanosleep */
 | 
			
		||||
 | 
			
		||||
#include <sys/mman.h>			/* Physical to virtual memory mapping */
 | 
			
		||||
 | 
			
		||||
@ -13,6 +14,7 @@
 | 
			
		||||
#include <minix/syslib.h>		/* sys_privctl */
 | 
			
		||||
 | 
			
		||||
#include <usb/hcd_common.h>
 | 
			
		||||
#include <usb/hcd_interface.h>
 | 
			
		||||
#include <usb/usb_common.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -159,6 +161,31 @@ hcd_os_clkconf_release(void)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    hcd_os_nanosleep                                                       *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
void
 | 
			
		||||
hcd_os_nanosleep(int nanosec)
 | 
			
		||||
{
 | 
			
		||||
	struct timespec nanotm;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	if (nanosec >= HCD_NANO) {
 | 
			
		||||
		nanotm.tv_sec = nanosec / HCD_NANO;
 | 
			
		||||
		nanotm.tv_nsec = nanosec % HCD_NANO;
 | 
			
		||||
	} else {
 | 
			
		||||
		nanotm.tv_sec = 0;
 | 
			
		||||
		nanotm.tv_nsec = nanosec;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* TODO: since it is not likely to be ever interrupted, we do not try
 | 
			
		||||
	 * to sleep for a remaining time in case of signal handling */
 | 
			
		||||
	USB_ASSERT(EXIT_SUCCESS == nanosleep(&nanotm, NULL),
 | 
			
		||||
		"Calling nanosleep() failed");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    hcd_init_device                                                        *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
@ -211,10 +238,19 @@ hcd_disconnect_device(hcd_device_state * this_device)
 | 
			
		||||
 *    hcd_device_wait                                                        *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
void
 | 
			
		||||
hcd_device_wait(hcd_device_state * this_device)
 | 
			
		||||
hcd_device_wait(hcd_device_state * this_device, hcd_event event, int ep)
 | 
			
		||||
{
 | 
			
		||||
	hcd_driver_state * drv;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	drv = (hcd_driver_state *)this_device->driver;
 | 
			
		||||
 | 
			
		||||
	drv->expected_event = event;
 | 
			
		||||
	drv->expected_endpoint = ep;
 | 
			
		||||
 | 
			
		||||
	USB_DBG("Waiting for: ev=0x%X, ep=0x%X", (int)event, ep);
 | 
			
		||||
 | 
			
		||||
	ddekit_sem_down(this_device->lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -225,8 +261,22 @@ hcd_device_wait(hcd_device_state * this_device)
 | 
			
		||||
void
 | 
			
		||||
hcd_device_continue(hcd_device_state * this_device)
 | 
			
		||||
{
 | 
			
		||||
	hcd_driver_state * drv;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	drv = (hcd_driver_state *)this_device->driver;
 | 
			
		||||
 | 
			
		||||
	/* We need to get what was expected... */
 | 
			
		||||
	USB_ASSERT(drv->current_event == drv->expected_event,
 | 
			
		||||
		"Unexpected event occurred");
 | 
			
		||||
 | 
			
		||||
	/* ...including endpoint interrupts */
 | 
			
		||||
	if (HCD_EVENT_ENDPOINT == drv->current_event) {
 | 
			
		||||
		USB_ASSERT(drv->current_endpoint == drv->expected_endpoint,
 | 
			
		||||
			"Unexpected endpoint interrupt");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ddekit_sem_up(this_device->lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -260,6 +310,11 @@ hcd_buffer_to_tree(hcd_reg1 * buf, int len, hcd_configuration * c)
 | 
			
		||||
		/* Check descriptor type */
 | 
			
		||||
		desc = (hcd_descriptor *)buf;
 | 
			
		||||
 | 
			
		||||
		if (0 == desc->bLength) {
 | 
			
		||||
			USB_MSG("Zero length descriptor");
 | 
			
		||||
			goto PARSE_ERROR;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (UDESC_CONFIG == desc->bDescriptorType) {
 | 
			
		||||
			if (EXIT_SUCCESS != hcd_fill_configuration(buf, len,
 | 
			
		||||
								c, cfg_num++))
 | 
			
		||||
@ -341,6 +396,36 @@ hcd_tree_cleanup(hcd_configuration * c)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    hcd_tree_find_ep                                                       *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
hcd_endpoint *
 | 
			
		||||
hcd_tree_find_ep(hcd_configuration * c, int ep)
 | 
			
		||||
{
 | 
			
		||||
	hcd_interface * i;
 | 
			
		||||
	hcd_endpoint * e;
 | 
			
		||||
	int if_idx;
 | 
			
		||||
	int ep_idx;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	/* Free if anything was allocated */
 | 
			
		||||
	USB_ASSERT(NULL != c->interface, "No interfaces available");
 | 
			
		||||
	USB_ASSERT(c->num_interfaces > 0, "Interface number error");
 | 
			
		||||
 | 
			
		||||
	for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) {
 | 
			
		||||
		i = &(c->interface[if_idx]);
 | 
			
		||||
		for (ep_idx = 0; ep_idx < i->num_endpoints; ep_idx++) {
 | 
			
		||||
			e = &(i->endpoint[ep_idx]);
 | 
			
		||||
			if (UE_GET_ADDR(e->descriptor.bEndpointAddress) == ep)
 | 
			
		||||
				return e;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    hcd_fill_configuration                                                 *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
@ -385,8 +470,7 @@ hcd_fill_configuration(hcd_reg1 * buf, int len, hcd_configuration * c, int num)
 | 
			
		||||
	USB_DBG("<<CONFIGURATION>>");
 | 
			
		||||
	USB_DBG("bLength %02X",			desc->bLength);
 | 
			
		||||
	USB_DBG("bDescriptorType %02X",		desc->bDescriptorType);
 | 
			
		||||
	USB_DBG("wTotalLength %02X%02X",	desc->wTotalLength[1],
 | 
			
		||||
						desc->wTotalLength[0]);
 | 
			
		||||
	USB_DBG("wTotalLength %04X",		UGETW(desc->wTotalLength));
 | 
			
		||||
	USB_DBG("bNumInterface %02X",		desc->bNumInterface);
 | 
			
		||||
	USB_DBG("bConfigurationValue %02X",	desc->bConfigurationValue);
 | 
			
		||||
	USB_DBG("iConfiguration %02X",		desc->iConfiguration);
 | 
			
		||||
@ -482,8 +566,7 @@ hcd_fill_endpoint(hcd_reg1 * buf, int len, hcd_endpoint * e, int num)
 | 
			
		||||
	USB_DBG("bDescriptorType %02X",		desc->bDescriptorType);
 | 
			
		||||
	USB_DBG("bEndpointAddress %02X",	desc->bEndpointAddress);
 | 
			
		||||
	USB_DBG("bmAttributes %02X",		desc->bmAttributes);
 | 
			
		||||
	USB_DBG("wMaxPacketSize %02X%02X",	desc->wMaxPacketSize[1],
 | 
			
		||||
						desc->wMaxPacketSize[0]);
 | 
			
		||||
	USB_DBG("wMaxPacketSize %04X",		UGETW(desc->wMaxPacketSize));
 | 
			
		||||
	USB_DBG("bInterval %02X",		desc->bInterval);
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@
 | 
			
		||||
#include <ddekit/usb.h>
 | 
			
		||||
 | 
			
		||||
#include <usb/hcd_ddekit.h>
 | 
			
		||||
#include <usb/hcd_interface.h>
 | 
			
		||||
#include <usb/usb_common.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -40,7 +41,7 @@ _ddekit_usb_get_manufacturer(struct ddekit_usb_dev * ddev)
 | 
			
		||||
{
 | 
			
		||||
	static const char mfg[] = "UNKNOWN";
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
	/* TODO: UNUSED won't work */
 | 
			
		||||
	/* TODO: UNUSED for argument won't work */
 | 
			
		||||
	((void)ddev);
 | 
			
		||||
	return (char *)mfg;
 | 
			
		||||
}
 | 
			
		||||
@ -54,7 +55,7 @@ _ddekit_usb_get_product(struct ddekit_usb_dev * ddev)
 | 
			
		||||
{
 | 
			
		||||
	static const char prod[] = "UNKNOWN";
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
	/* TODO: UNUSED won't work */
 | 
			
		||||
	/* TODO: UNUSED for argument won't work */
 | 
			
		||||
	((void)ddev);
 | 
			
		||||
	return (char *)prod;
 | 
			
		||||
}
 | 
			
		||||
@ -68,7 +69,7 @@ _ddekit_usb_get_serial(struct ddekit_usb_dev * ddev)
 | 
			
		||||
{
 | 
			
		||||
	static const char serial[] = "UNKNOWN";
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
	/* TODO: UNUSED won't work */
 | 
			
		||||
	/* TODO: UNUSED for argument won't work */
 | 
			
		||||
	((void)ddev);
 | 
			
		||||
	return (char *)serial;
 | 
			
		||||
}
 | 
			
		||||
@ -156,7 +157,7 @@ ddekit_usb_get_device_id(struct ddekit_usb_dev * dev,
 | 
			
		||||
			struct ddekit_usb_device_id * id)
 | 
			
		||||
{
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
	/* TODO: UNUSED won't work */
 | 
			
		||||
	/* TODO: UNUSED for argument won't work */
 | 
			
		||||
	((void)dev);
 | 
			
		||||
	((void)id);
 | 
			
		||||
	return;
 | 
			
		||||
@ -172,17 +173,19 @@ ddekit_usb_submit_urb(struct ddekit_usb_urb * d_urb)
 | 
			
		||||
{
 | 
			
		||||
	hcd_urb * urb;
 | 
			
		||||
	hcd_device_state * dev;
 | 
			
		||||
	hcd_driver_state * drv;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	urb = (hcd_urb *)d_urb;
 | 
			
		||||
	dev = (hcd_device_state *)(urb->dev);
 | 
			
		||||
	drv = (hcd_driver_state *)(dev->driver);
 | 
			
		||||
 | 
			
		||||
	/* TODO: queue URB's */
 | 
			
		||||
	/* Reassign and go to thread */
 | 
			
		||||
	dev->urb = urb;
 | 
			
		||||
	hcd_device_continue(dev);
 | 
			
		||||
	dev->urb = NULL;
 | 
			
		||||
	drv->current_event = HCD_EVENT_URB;
 | 
			
		||||
 | 
			
		||||
	/* TODO: URB's must be queued somewhere */
 | 
			
		||||
	hcd_handle_event(drv);
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@ -195,7 +198,7 @@ int
 | 
			
		||||
ddekit_usb_cancle_urb(struct ddekit_usb_urb * d_urb)
 | 
			
		||||
{
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
	/* TODO: UNUSED won't work */
 | 
			
		||||
	/* TODO: UNUSED for argument won't work */
 | 
			
		||||
	((void)d_urb);
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,6 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>					/* memset */
 | 
			
		||||
#include <time.h>					/* nanosleep */
 | 
			
		||||
 | 
			
		||||
#include <usb/hcd_common.h>
 | 
			
		||||
#include <usb/hcd_platforms.h>
 | 
			
		||||
@ -19,17 +18,19 @@
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    AM335x base register defines                                           *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
/* Where MUSB core space starts */
 | 
			
		||||
#define AM335X_MUSB_CORE0_BASE_ADDR		0x47401400u
 | 
			
		||||
#define AM335X_MUSB_CORE1_BASE_ADDR		0x47401C00u
 | 
			
		||||
#define AM335X_MUSB_CORE_BASE_LEN		0x400u
 | 
			
		||||
/* Memory placement defines */
 | 
			
		||||
#define AM335X_USBSS_BASE_ADDR			0x47400000u
 | 
			
		||||
#define AM335X_USB0_BASE_OFFSET			0x1000u
 | 
			
		||||
#define AM335X_MUSB_CORE0_BASE_OFFSET		0x1400u
 | 
			
		||||
#define AM335X_USB1_BASE_OFFSET			0x1800u
 | 
			
		||||
#define AM335X_MUSB_CORE1_BASE_OFFSET		0x1C00u
 | 
			
		||||
#define AM335X_USBSS_TOTAL_REG_LEN		0x5000u
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    AM335x USB specific register defines                                   *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
/* SS registers base address */
 | 
			
		||||
#define AM335X_USBSS_BASE_ADDR			0x47400000u
 | 
			
		||||
 | 
			
		||||
#define AM335X_REG_REVREG			0x000u
 | 
			
		||||
#define AM335X_REG_SYSCONFIG			0x010u
 | 
			
		||||
@ -74,13 +75,6 @@
 | 
			
		||||
#define AM335X_REG_IRQFRAMEENABLE0		0x240u
 | 
			
		||||
#define AM335X_REG_IRQFRAMEENABLE1		0x244u
 | 
			
		||||
 | 
			
		||||
/* Length in bytes of SS registers */
 | 
			
		||||
#define AM335X_USBSS_BASE_LEN			AM335X_REG_IRQFRAMEENABLE1 + 4u
 | 
			
		||||
 | 
			
		||||
/* USBx registers base addresses */
 | 
			
		||||
#define AM335X_USB0_BASE_ADDR			0x47401000u
 | 
			
		||||
#define AM335X_USB1_BASE_ADDR			0x47401800u
 | 
			
		||||
 | 
			
		||||
#define AM335X_REG_USBXREV			0x00u
 | 
			
		||||
#define AM335X_REG_USBXCTRL			0x14u
 | 
			
		||||
#define AM335X_REG_USBXSTAT			0x18u
 | 
			
		||||
@ -167,6 +161,22 @@
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_DRVVBUS		HCD_BIT(8)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_GENERIC		HCD_BIT(9)
 | 
			
		||||
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_1		HCD_BIT(17)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_2		HCD_BIT(18)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_3		HCD_BIT(19)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_4		HCD_BIT(20)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_5		HCD_BIT(21)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_6		HCD_BIT(22)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_7		HCD_BIT(23)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_8		HCD_BIT(24)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_9		HCD_BIT(25)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_10		HCD_BIT(26)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_11		HCD_BIT(27)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_12		HCD_BIT(28)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_13		HCD_BIT(29)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_14		HCD_BIT(30)
 | 
			
		||||
#define AM335X_VAL_USBXIRQENABLEXXX1_TX_FIFO_15		HCD_BIT(31)
 | 
			
		||||
 | 
			
		||||
#define AM335X_VAL_USBXIRQSTAT1_SUSPEND		HCD_BIT(0)
 | 
			
		||||
#define AM335X_VAL_USBXIRQSTAT1_RESUME		HCD_BIT(1)
 | 
			
		||||
#define AM335X_VAL_USBXIRQSTAT1_RESET_BABBLE	HCD_BIT(2)
 | 
			
		||||
@ -178,9 +188,6 @@
 | 
			
		||||
#define AM335X_VAL_USBXIRQSTAT1_DRVVBUS		HCD_BIT(8)
 | 
			
		||||
#define AM335X_VAL_USBXIRQSTAT1_GENERIC		HCD_BIT(9)
 | 
			
		||||
 | 
			
		||||
/* Length in bytes of USBx registers */
 | 
			
		||||
#define AM335X_USBX_BASE_LEN			AM335X_REG_USBXMODE + 4u
 | 
			
		||||
 | 
			
		||||
/* Helpers for interrupt clearing */
 | 
			
		||||
#define CLEAR_IRQ0(irq0_bit)	HCD_WR4(r, AM335X_REG_USBXIRQSTAT0, (irq0_bit))
 | 
			
		||||
#define CLEAR_IRQ1(irq1_bit)	HCD_WR4(r, AM335X_REG_USBXIRQSTAT1, (irq1_bit))
 | 
			
		||||
@ -263,6 +270,7 @@ static void musb_am335x_internal_deinit(void);
 | 
			
		||||
static void musb_am335x_irq_init(void *); /* TODO: required by DDEKit */
 | 
			
		||||
static void musb_am335x_usbss_isr(void *);
 | 
			
		||||
static void musb_am335x_usbx_isr(void *);
 | 
			
		||||
static int musb_am335x_irqstat0_to_ep(int);
 | 
			
		||||
 | 
			
		||||
/* Configuration helpers */
 | 
			
		||||
static void musb_am335x_usb_reset(int);
 | 
			
		||||
@ -289,7 +297,7 @@ musb_am335x_init(void)
 | 
			
		||||
 | 
			
		||||
	/* Map memory for USBSS */
 | 
			
		||||
	am335x.ss.regs = hcd_os_regs_init(AM335X_USBSS_BASE_ADDR,
 | 
			
		||||
					AM335X_USBSS_BASE_LEN);
 | 
			
		||||
					AM335X_USBSS_TOTAL_REG_LEN);
 | 
			
		||||
 | 
			
		||||
	if (NULL == am335x.ss.regs)
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
@ -312,18 +320,12 @@ musb_am335x_init(void)
 | 
			
		||||
		ctrl->priv.usb_num = AM335X_USB0;
 | 
			
		||||
 | 
			
		||||
		/* MUSB core addresses for later registering */
 | 
			
		||||
		ctrl->core.regs = hcd_os_regs_init(AM335X_MUSB_CORE0_BASE_ADDR,
 | 
			
		||||
						AM335X_MUSB_CORE_BASE_LEN);
 | 
			
		||||
 | 
			
		||||
		if (NULL == ctrl->core.regs)
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		ctrl->core.regs = (void*)((hcd_addr)am335x.ss.regs +
 | 
			
		||||
					AM335X_MUSB_CORE0_BASE_OFFSET);
 | 
			
		||||
 | 
			
		||||
		/* Map AM335X USB0 specific addresses */
 | 
			
		||||
		ctrl->usb.regs = hcd_os_regs_init(AM335X_USB0_BASE_ADDR,
 | 
			
		||||
						AM335X_USBX_BASE_LEN);
 | 
			
		||||
 | 
			
		||||
		if (NULL == ctrl->usb.regs)
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		ctrl->usb.regs = (void*)((hcd_addr)am335x.ss.regs +
 | 
			
		||||
					AM335X_USB0_BASE_OFFSET);
 | 
			
		||||
 | 
			
		||||
		/* Attach IRQ to number */
 | 
			
		||||
		if (EXIT_SUCCESS != hcd_os_interrupt_attach(AM335X_USB0_IRQ,
 | 
			
		||||
@ -337,6 +339,8 @@ musb_am335x_init(void)
 | 
			
		||||
		ctrl->driver.setup_device = musb_setup_device;
 | 
			
		||||
		ctrl->driver.reset_device = musb_reset_device;
 | 
			
		||||
		ctrl->driver.setup_stage = musb_setup_stage;
 | 
			
		||||
		ctrl->driver.bulk_in_stage = musb_bulk_in_stage;
 | 
			
		||||
		ctrl->driver.bulk_out_stage = musb_bulk_out_stage;
 | 
			
		||||
		ctrl->driver.in_data_stage = musb_in_data_stage;
 | 
			
		||||
		ctrl->driver.out_data_stage = musb_out_data_stage;
 | 
			
		||||
		ctrl->driver.in_status_stage = musb_in_status_stage;
 | 
			
		||||
@ -356,18 +360,12 @@ musb_am335x_init(void)
 | 
			
		||||
		ctrl->priv.usb_num = AM335X_USB1;
 | 
			
		||||
 | 
			
		||||
		/* MUSB core addresses for later registering */
 | 
			
		||||
		ctrl->core.regs = hcd_os_regs_init(AM335X_MUSB_CORE1_BASE_ADDR,
 | 
			
		||||
						AM335X_MUSB_CORE_BASE_LEN);
 | 
			
		||||
		ctrl->core.regs = (void*)((hcd_addr)am335x.ss.regs +
 | 
			
		||||
					AM335X_MUSB_CORE1_BASE_OFFSET);
 | 
			
		||||
 | 
			
		||||
		if (NULL == ctrl->core.regs)
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
 | 
			
		||||
		/* Map AM335X USB1 specific addresses */
 | 
			
		||||
		ctrl->usb.regs = hcd_os_regs_init(AM335X_USB1_BASE_ADDR,
 | 
			
		||||
						AM335X_USBX_BASE_LEN);
 | 
			
		||||
 | 
			
		||||
		if (NULL == ctrl->usb.regs)
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		/* Map AM335X USB0 specific addresses */
 | 
			
		||||
		ctrl->usb.regs = (void*)((hcd_addr)am335x.ss.regs +
 | 
			
		||||
					AM335X_USB1_BASE_OFFSET);
 | 
			
		||||
 | 
			
		||||
		/* Attach IRQ to number */
 | 
			
		||||
		if (EXIT_SUCCESS != hcd_os_interrupt_attach(AM335X_USB1_IRQ,
 | 
			
		||||
@ -381,6 +379,8 @@ musb_am335x_init(void)
 | 
			
		||||
		ctrl->driver.setup_device = musb_setup_device;
 | 
			
		||||
		ctrl->driver.reset_device = musb_reset_device;
 | 
			
		||||
		ctrl->driver.setup_stage = musb_setup_stage;
 | 
			
		||||
		ctrl->driver.bulk_in_stage = musb_bulk_in_stage;
 | 
			
		||||
		ctrl->driver.bulk_out_stage = musb_bulk_out_stage;
 | 
			
		||||
		ctrl->driver.in_data_stage = musb_in_data_stage;
 | 
			
		||||
		ctrl->driver.out_data_stage = musb_out_data_stage;
 | 
			
		||||
		ctrl->driver.in_status_stage = musb_in_status_stage;
 | 
			
		||||
@ -404,32 +404,9 @@ musb_am335x_deinit(void)
 | 
			
		||||
	musb_am335x_internal_deinit();
 | 
			
		||||
 | 
			
		||||
	/* Release maps if anything was assigned */
 | 
			
		||||
#ifdef AM335X_USE_USB0
 | 
			
		||||
	if (NULL != am335x.ctrl[AM335X_USB0].usb.regs)
 | 
			
		||||
		if (EXIT_SUCCESS != hcd_os_regs_deinit(AM335X_USB0_BASE_ADDR,
 | 
			
		||||
							AM335X_USBX_BASE_LEN))
 | 
			
		||||
			USB_MSG("Failed to release USB0 OTG mapping");
 | 
			
		||||
 | 
			
		||||
	if (NULL != am335x.ctrl[AM335X_USB0].core.regs)
 | 
			
		||||
		if (EXIT_SUCCESS != hcd_os_regs_deinit(
 | 
			
		||||
						AM335X_MUSB_CORE0_BASE_ADDR,
 | 
			
		||||
						AM335X_MUSB_CORE_BASE_LEN))
 | 
			
		||||
			USB_MSG("Failed to release USB0 core mapping");
 | 
			
		||||
#endif
 | 
			
		||||
	if (NULL != am335x.ctrl[AM335X_USB1].usb.regs)
 | 
			
		||||
		if (EXIT_SUCCESS != hcd_os_regs_deinit(AM335X_USB1_BASE_ADDR,
 | 
			
		||||
							AM335X_USBX_BASE_LEN))
 | 
			
		||||
			USB_MSG("Failed to release USB1 OTG mapping");
 | 
			
		||||
 | 
			
		||||
	if (NULL != am335x.ctrl[AM335X_USB1].core.regs)
 | 
			
		||||
		if (EXIT_SUCCESS != hcd_os_regs_deinit(
 | 
			
		||||
						AM335X_MUSB_CORE1_BASE_ADDR,
 | 
			
		||||
						AM335X_MUSB_CORE_BASE_LEN))
 | 
			
		||||
			USB_MSG("Failed to release USB1 core mapping");
 | 
			
		||||
 | 
			
		||||
	if (NULL != am335x.ss.regs)
 | 
			
		||||
		if (EXIT_SUCCESS != hcd_os_regs_deinit(AM335X_USBSS_BASE_ADDR,
 | 
			
		||||
							AM335X_USBSS_BASE_LEN))
 | 
			
		||||
						AM335X_USBSS_TOTAL_REG_LEN))
 | 
			
		||||
			USB_MSG("Failed to release USBSS mapping");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -449,14 +426,11 @@ musb_am335x_internal_init(void)
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
 | 
			
		||||
	/* TODO: time to stabilize? */
 | 
			
		||||
	{
 | 
			
		||||
		/* Sleep 25ms */
 | 
			
		||||
		struct timespec nanotm = {0, HCD_NANOSLEEP_MSEC(25)};
 | 
			
		||||
		nanosleep(&nanotm, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	/* Sleep 25msec */
 | 
			
		||||
	hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(25));
 | 
			
		||||
 | 
			
		||||
	/* Read and dump revision register */
 | 
			
		||||
	USB_MSG("Revision (REVREG): %08X",
 | 
			
		||||
	USB_MSG("MUSB revision (REVREG): %08X",
 | 
			
		||||
		(unsigned int)HCD_RD4(am335x.ss.regs, AM335X_REG_REVREG));
 | 
			
		||||
 | 
			
		||||
	/* Allow OS to handle previously configured USBSS interrupts */
 | 
			
		||||
@ -469,8 +443,6 @@ musb_am335x_internal_init(void)
 | 
			
		||||
	hcd_os_interrupt_enable(AM335X_USB0_IRQ);
 | 
			
		||||
	/* Enable whatever necessary for OTG part of controller */
 | 
			
		||||
	musb_am335x_otg_enable(AM335X_USB0);
 | 
			
		||||
	/* Configure control endpoint EP0 */
 | 
			
		||||
	musb_ep0_config(&(am335x.ctrl[AM335X_USB0].core));
 | 
			
		||||
	/* Start actual MUSB core */
 | 
			
		||||
	musb_core_start(&(am335x.ctrl[AM335X_USB0].core));
 | 
			
		||||
#endif
 | 
			
		||||
@ -481,8 +453,6 @@ musb_am335x_internal_init(void)
 | 
			
		||||
	hcd_os_interrupt_enable(AM335X_USB1_IRQ);
 | 
			
		||||
	/* Enable whatever necessary for OTG part of controller */
 | 
			
		||||
	musb_am335x_otg_enable(AM335X_USB1);
 | 
			
		||||
	/* Configure control endpoint EP0 */
 | 
			
		||||
	musb_ep0_config(&(am335x.ctrl[AM335X_USB1].core));
 | 
			
		||||
	/* Start actual MUSB core */
 | 
			
		||||
	musb_core_start(&(am335x.ctrl[AM335X_USB1].core));
 | 
			
		||||
 | 
			
		||||
@ -581,8 +551,7 @@ musb_am335x_usbx_isr(void * data)
 | 
			
		||||
	if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED) {
 | 
			
		||||
		USB_DBG("Device connected");
 | 
			
		||||
		CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED);
 | 
			
		||||
		driver->event = HCD_EVENT_CONNECTED;
 | 
			
		||||
		driver->subevent = HCD_SUBEVENT_NONE;
 | 
			
		||||
		driver->current_event = HCD_EVENT_CONNECTED;
 | 
			
		||||
		hcd_handle_event(driver);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
@ -590,17 +559,16 @@ musb_am335x_usbx_isr(void * data)
 | 
			
		||||
	if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED) {
 | 
			
		||||
		USB_DBG("Device disconnected");
 | 
			
		||||
		CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED);
 | 
			
		||||
		driver->event = HCD_EVENT_DISCONNECTED;
 | 
			
		||||
		driver->subevent = HCD_SUBEVENT_NONE;
 | 
			
		||||
		driver->current_event = HCD_EVENT_DISCONNECTED;
 | 
			
		||||
		hcd_handle_event(driver);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (irqstat0 & 0x01) {
 | 
			
		||||
		USB_DBG("EP0 interrupt");
 | 
			
		||||
		CLEAR_IRQ0(0x01);
 | 
			
		||||
		driver->event = HCD_EVENT_ENDPOINT;
 | 
			
		||||
		driver->subevent = HCD_SUBEVENT_EP0;
 | 
			
		||||
	if (0 != irqstat0) {
 | 
			
		||||
		USB_DBG("EP interrupt");
 | 
			
		||||
		CLEAR_IRQ0(irqstat0);
 | 
			
		||||
		driver->current_event = HCD_EVENT_ENDPOINT;
 | 
			
		||||
		driver->current_endpoint = musb_am335x_irqstat0_to_ep(irqstat0);
 | 
			
		||||
		hcd_handle_event(driver);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
@ -654,6 +622,34 @@ musb_am335x_usbx_isr(void * data)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    musb_am335x_irqstat0_to_ep                                             *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static int
 | 
			
		||||
musb_am335x_irqstat0_to_ep(int irqstat0)
 | 
			
		||||
{
 | 
			
		||||
	int ep;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	ep = 0;
 | 
			
		||||
 | 
			
		||||
	while (0 == (irqstat0 & 0x01)) {
 | 
			
		||||
		irqstat0 >>= 1;
 | 
			
		||||
		ep++;
 | 
			
		||||
		USB_ASSERT(ep < 32, "Invalid IRQSTAT0 supplied (1)");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Convert RX interrupt to EP number */
 | 
			
		||||
	if (ep >= 16) {
 | 
			
		||||
		ep -= 16;
 | 
			
		||||
		USB_ASSERT(ep != 0, "Invalid IRQSTAT0 supplied (2)");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ep;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    musb_am335x_usb_reset                                                  *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
@ -711,8 +707,47 @@ musb_am335x_otg_enable(int usb_num)
 | 
			
		||||
 | 
			
		||||
	HCD_WR4(r, AM335X_REG_USBXIRQENABLESET1, intreg);
 | 
			
		||||
 | 
			
		||||
	/* Set endpoint 0 interrupt to be enabled */
 | 
			
		||||
	/* Some MUSB implementations may not need this */
 | 
			
		||||
#if 0
 | 
			
		||||
	/* Set EP0 interrupt to be enabled */
 | 
			
		||||
	intreg = HCD_RD4(r, AM335X_REG_USBXIRQENABLESET0);
 | 
			
		||||
	HCD_SET(intreg, AM335X_VAL_USBXIRQENABLEXXX0_EP0);
 | 
			
		||||
	HCD_WR4(r, AM335X_REG_USBXIRQENABLESET0, intreg);
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
	/* Set all EP interrupts as enabled */
 | 
			
		||||
	intreg = AM335X_VAL_USBXIRQENABLEXXX0_EP0	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP1	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP2	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP3	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP4	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP5	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP6	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP7	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP8	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP9	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP10	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP11	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP12	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP13	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP14	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_TX_EP15	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP1	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP2	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP3	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP4	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP5	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP6	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP7	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP8	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP9	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP10	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP11	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP12	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP13	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP14	|
 | 
			
		||||
		AM335X_VAL_USBXIRQENABLEXXX0_RX_EP15	;
 | 
			
		||||
 | 
			
		||||
	HCD_WR4(r, AM335X_REG_USBXIRQENABLESET0, intreg);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,6 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <string.h>				/* memcpy */
 | 
			
		||||
#include <time.h>				/* nanosleep */
 | 
			
		||||
 | 
			
		||||
#include <usb/hcd_common.h>
 | 
			
		||||
#include <usb/hcd_interface.h>
 | 
			
		||||
@ -13,23 +12,17 @@
 | 
			
		||||
#include "musb_regs.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    Local defines                                                          *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
#define HCD_COPYBUF_BYTES 64 /* Stack allocated, must be multiple of 4 */
 | 
			
		||||
#define HCD_COPYBUF_WORDS (HCD_COPYBUF_BYTES/4)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    Local prototypes                                                       *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static void musb_set_state(musb_core_config *);
 | 
			
		||||
static int musb_check_rxpktrdy(void *);
 | 
			
		||||
static void musb_in_stage_cleanup(void *);
 | 
			
		||||
static void musb_clear_rxpktrdy(void *);
 | 
			
		||||
static int musb_check_rxpktrdy(void *, int);
 | 
			
		||||
static void musb_in_stage_cleanup(void *, int);
 | 
			
		||||
static void musb_clear_rxpktrdy(void *, int);
 | 
			
		||||
static void musb_clear_statuspkt(void *);
 | 
			
		||||
static int musb_get_count(void *);
 | 
			
		||||
static void musb_read_fifo(void *, hcd_reg1 *, int, int);
 | 
			
		||||
static void musb_read_fifo(void *, void *, int, int);
 | 
			
		||||
static void musb_write_fifo(void *, void *, int, int);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
@ -45,23 +38,23 @@ static void
 | 
			
		||||
musb_set_state(musb_core_config * cfg)
 | 
			
		||||
{
 | 
			
		||||
	void * r;
 | 
			
		||||
	hcd_reg1 idx;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	r = cfg->regs;
 | 
			
		||||
 | 
			
		||||
	USB_ASSERT(cfg->ep <= 15, "Invalid EP supplied");
 | 
			
		||||
	USB_ASSERT(cfg->addr <= 127, "Invalid device address supplied");
 | 
			
		||||
 | 
			
		||||
	/* Set EP and address to be used in next MUSB command */
 | 
			
		||||
 | 
			
		||||
	/* Set EP by selecting INDEX */
 | 
			
		||||
	idx = HCD_RD1(r, MUSB_REG_INDEX);
 | 
			
		||||
	HCD_CLR(idx, 0x0F);
 | 
			
		||||
	HCD_SET(idx, cfg->ep & 0x0F);
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_INDEX, idx);
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_INDEX, cfg->ep);
 | 
			
		||||
 | 
			
		||||
	/* Use device with address 'cfg->addr' */
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_RXFUNCADDR, cfg->addr);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_TXFUNCADDR, cfg->addr);
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_FADDR, cfg->addr);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_CONFIG(cfg->ep, MUSB_REG_RXFUNCADDR), cfg->addr);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_CONFIG(cfg->ep, MUSB_REG_TXFUNCADDR), cfg->addr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -69,10 +62,9 @@ musb_set_state(musb_core_config * cfg)
 | 
			
		||||
 *    musb_check_rxpktrdy                                                    *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static int
 | 
			
		||||
musb_check_rxpktrdy(void * cfg)
 | 
			
		||||
musb_check_rxpktrdy(void * cfg, int ep_num)
 | 
			
		||||
{
 | 
			
		||||
	void * r;
 | 
			
		||||
	hcd_reg2 host_csr0;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
@ -81,12 +73,18 @@ musb_check_rxpktrdy(void * cfg)
 | 
			
		||||
	/* Set EP and device address to be used in this command */
 | 
			
		||||
	musb_set_state((musb_core_config *)cfg);
 | 
			
		||||
 | 
			
		||||
	/* Get control status register for EP 0 */
 | 
			
		||||
	host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0);
 | 
			
		||||
 | 
			
		||||
	/* Check for RXPKTRDY */
 | 
			
		||||
	if (host_csr0 & MUSB_VAL_HOST_CSR0_RXPKTRDY)
 | 
			
		||||
		return EXIT_SUCCESS;
 | 
			
		||||
	if (0 == ep_num) {
 | 
			
		||||
		/* Get control status register for EP 0 */
 | 
			
		||||
		if (HCD_RD2(r, MUSB_REG_HOST_CSR0) &
 | 
			
		||||
			MUSB_VAL_HOST_CSR0_RXPKTRDY)
 | 
			
		||||
			return EXIT_SUCCESS;
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Get RX status register for any other EP */
 | 
			
		||||
		if (HCD_RD2(r, MUSB_REG_HOST_RXCSR) &
 | 
			
		||||
			MUSB_VAL_HOST_RXCSR_RXPKTRDY)
 | 
			
		||||
			return EXIT_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return EXIT_FAILURE;
 | 
			
		||||
}
 | 
			
		||||
@ -96,12 +94,15 @@ musb_check_rxpktrdy(void * cfg)
 | 
			
		||||
 *    musb_in_stage_cleanup                                                  *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static void
 | 
			
		||||
musb_in_stage_cleanup(void * cfg)
 | 
			
		||||
musb_in_stage_cleanup(void * cfg, int ep_num)
 | 
			
		||||
{
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	musb_clear_rxpktrdy(cfg);
 | 
			
		||||
	musb_clear_statuspkt(cfg);
 | 
			
		||||
	musb_clear_rxpktrdy(cfg, ep_num);
 | 
			
		||||
 | 
			
		||||
	/* For control EP 0 also clear STATUSPKT */
 | 
			
		||||
	if (0 == ep_num)
 | 
			
		||||
		musb_clear_statuspkt(cfg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -109,10 +110,10 @@ musb_in_stage_cleanup(void * cfg)
 | 
			
		||||
 *    musb_clear_rxpktrdy                                                    *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static void
 | 
			
		||||
musb_clear_rxpktrdy(void * cfg)
 | 
			
		||||
musb_clear_rxpktrdy(void * cfg, int ep_num)
 | 
			
		||||
{
 | 
			
		||||
	void * r;
 | 
			
		||||
	hcd_reg2 host_csr0;
 | 
			
		||||
	hcd_reg2 host_csr;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
@ -121,12 +122,22 @@ musb_clear_rxpktrdy(void * cfg)
 | 
			
		||||
	/* Set EP and device address to be used in this command */
 | 
			
		||||
	musb_set_state((musb_core_config *)cfg);
 | 
			
		||||
 | 
			
		||||
	/* Get control status register for EP 0 */
 | 
			
		||||
	host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0);
 | 
			
		||||
	/* Check for RXPKTRDY */
 | 
			
		||||
	if (0 == ep_num) {
 | 
			
		||||
		/* Get control status register for EP 0 */
 | 
			
		||||
		host_csr = HCD_RD2(r, MUSB_REG_HOST_CSR0);
 | 
			
		||||
 | 
			
		||||
	/* Clear RXPKTRDY to signal receive completion */
 | 
			
		||||
	HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_RXPKTRDY);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
 | 
			
		||||
		/* Clear RXPKTRDY to signal receive completion */
 | 
			
		||||
		HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_RXPKTRDY);
 | 
			
		||||
		HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr);
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Get RX status register for any other EP */
 | 
			
		||||
		host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
 | 
			
		||||
 | 
			
		||||
		/* Clear RXPKTRDY to signal receive completion */
 | 
			
		||||
		HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_RXPKTRDY);
 | 
			
		||||
		HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -180,41 +191,92 @@ musb_get_count(void * cfg)
 | 
			
		||||
 *    musb_read_fifo                                                         *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static void
 | 
			
		||||
musb_read_fifo(void * cfg, hcd_reg1 * output, int size, int fifo_num)
 | 
			
		||||
musb_read_fifo(void * cfg, void * output, int size, int fifo_num)
 | 
			
		||||
{
 | 
			
		||||
	void * r;
 | 
			
		||||
	hcd_reg4 * word;
 | 
			
		||||
	hcd_reg4 copy_buf[HCD_COPYBUF_WORDS];
 | 
			
		||||
 | 
			
		||||
	hcd_reg1 * output_b;
 | 
			
		||||
	hcd_reg4 * output_w;
 | 
			
		||||
 | 
			
		||||
	hcd_addr fifo_addr;
 | 
			
		||||
	int limit;
 | 
			
		||||
	int idx;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	USB_ASSERT((fifo_num >= 0) && (fifo_num <= 4), "Wrong FIFO number");
 | 
			
		||||
	USB_ASSERT((fifo_num >= 0) && (fifo_num <= 15), "Wrong FIFO number");
 | 
			
		||||
 | 
			
		||||
	r = ((musb_core_config *)cfg)->regs;
 | 
			
		||||
	fifo_addr = MUSB_REG_FIFO0 + (fifo_num * MUSB_REG_FIFO_LEN);
 | 
			
		||||
 | 
			
		||||
	/* Set EP and device address to be used in this command */
 | 
			
		||||
	musb_set_state((musb_core_config *)cfg);
 | 
			
		||||
	/* TODO: Apparently, FIFO can only be read by:
 | 
			
		||||
	 * 1. initially using words
 | 
			
		||||
	 * 2. using bytes for whatever remains
 | 
			
		||||
	 * Reading bytes first to achieve alignment of remaining data
 | 
			
		||||
	 * will for some reason disable further word based reading
 | 
			
		||||
	 * Such reading method, may not be optimal for unaligned data */
 | 
			
		||||
	output_w = (hcd_reg4 *)output;
 | 
			
		||||
 | 
			
		||||
	/* Read full words from MUSB FIFO */
 | 
			
		||||
	/* Try and copy aligned words */
 | 
			
		||||
	if (0 == ((hcd_addr)output_w % 4)) {
 | 
			
		||||
 | 
			
		||||
		while (size > (int)(sizeof(*output_w) - 1)) {
 | 
			
		||||
			*output_w++ = HCD_RD4(r, fifo_addr);
 | 
			
		||||
			size -= sizeof(*output_w);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	output_b = (hcd_reg1 *)output_w;
 | 
			
		||||
 | 
			
		||||
	/* Then, go with remaining bytes */
 | 
			
		||||
	while (size > 0) {
 | 
			
		||||
		/* Largest amount of bytes that can be copied at a time */
 | 
			
		||||
		limit = (size < HCD_COPYBUF_BYTES) ? size : HCD_COPYBUF_BYTES;
 | 
			
		||||
		*output_b++ = HCD_RD1(r, fifo_addr);
 | 
			
		||||
		size--;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		/* Start copying into that */
 | 
			
		||||
		word = copy_buf;
 | 
			
		||||
 | 
			
		||||
		/* Read words from FIFO into copy_buf */
 | 
			
		||||
		for (idx = 0; idx < limit; idx += sizeof(*word))
 | 
			
		||||
			*word++ = HCD_RD4(r, fifo_addr);
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    musb_write_fifo                                                         *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
static void
 | 
			
		||||
musb_write_fifo(void * cfg, void * input, int size, int fifo_num)
 | 
			
		||||
{
 | 
			
		||||
	void * r;
 | 
			
		||||
 | 
			
		||||
		/* Copy and shift */
 | 
			
		||||
		memcpy(output, copy_buf, limit);
 | 
			
		||||
		output += limit;
 | 
			
		||||
		size -= limit;
 | 
			
		||||
	hcd_reg1 * input_b;
 | 
			
		||||
	hcd_reg4 * input_w;
 | 
			
		||||
 | 
			
		||||
	hcd_addr fifo_addr;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	USB_ASSERT((fifo_num >= 0) && (fifo_num <= 15), "Wrong FIFO number");
 | 
			
		||||
 | 
			
		||||
	r = ((musb_core_config *)cfg)->regs;
 | 
			
		||||
	fifo_addr = MUSB_REG_FIFO0 + (fifo_num * MUSB_REG_FIFO_LEN);
 | 
			
		||||
 | 
			
		||||
	/* TODO: Apparently, FIFO can only be written by:
 | 
			
		||||
	 * 1. initially using words
 | 
			
		||||
	 * 2. using bytes for whatever remains
 | 
			
		||||
	 * Writing bytes first to achieve alignment of remaining data
 | 
			
		||||
	 * will for some reason disable further word based writing
 | 
			
		||||
	 * Such writing method, may not be optimal for unaligned data */
 | 
			
		||||
	input_w = (hcd_reg4 *)input;
 | 
			
		||||
 | 
			
		||||
	/* Try and copy aligned words */
 | 
			
		||||
	if (0 == ((hcd_addr)input_w % 4)) {
 | 
			
		||||
 | 
			
		||||
		while (size > (int)(sizeof(*input_w) - 1)) {
 | 
			
		||||
			HCD_WR4(r, fifo_addr, *input_w++);
 | 
			
		||||
			size -= sizeof(*input_w);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_b = (hcd_reg1 *)input_w;
 | 
			
		||||
 | 
			
		||||
	/* Then, go with remaining bytes */
 | 
			
		||||
	while (size > 0) {
 | 
			
		||||
		HCD_WR1(r, fifo_addr, *input_b++);
 | 
			
		||||
		size--;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -272,41 +334,6 @@ musb_core_stop(void * cfg)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    musb_ep0_config                                                        *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
void
 | 
			
		||||
musb_ep0_config(void * cfg)
 | 
			
		||||
{
 | 
			
		||||
	void * r;
 | 
			
		||||
	hcd_reg1 host_type0;
 | 
			
		||||
	hcd_reg2 intrtxe;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	r = ((musb_core_config *)cfg)->regs;
 | 
			
		||||
 | 
			
		||||
	/* Set parameters temporarily */
 | 
			
		||||
	musb_setup_device((musb_core_config *)cfg,
 | 
			
		||||
			HCD_DEFAULT_EP,
 | 
			
		||||
			HCD_DEFAULT_ADDR);
 | 
			
		||||
 | 
			
		||||
	/* Set EP and device address to be used in this command */
 | 
			
		||||
	musb_set_state((musb_core_config *)cfg);
 | 
			
		||||
 | 
			
		||||
	/* Set high speed for EP0 */
 | 
			
		||||
	host_type0 = HCD_RD1(r, MUSB_REG_HOST_TYPE0);
 | 
			
		||||
	HCD_CLR(host_type0, MUSB_VAL_HOST_TYPE0_MASK);
 | 
			
		||||
	HCD_SET(host_type0, MUSB_VAL_HOST_TYPE0_HIGH_SPEED);
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_HOST_TYPE0, host_type0);
 | 
			
		||||
 | 
			
		||||
	/* Enable EP interrupt */
 | 
			
		||||
	intrtxe = HCD_RD2(r, MUSB_REG_INTRTXE);
 | 
			
		||||
	HCD_SET(intrtxe, MUSB_VAL_INTRTXE_EP0);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_INTRTXE, intrtxe);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *                                                                           *
 | 
			
		||||
 *    HCD interface implementation                                           *
 | 
			
		||||
@ -330,15 +357,24 @@ musb_setup_device(void * cfg, hcd_reg1 ep, hcd_reg1 addr)
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    musb_reset_device                                                      *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
void
 | 
			
		||||
musb_reset_device(void * cfg)
 | 
			
		||||
int
 | 
			
		||||
musb_reset_device(void * cfg, hcd_speed * speed)
 | 
			
		||||
{
 | 
			
		||||
	void * r;
 | 
			
		||||
	musb_core_config * core;
 | 
			
		||||
	hcd_reg1 power;
 | 
			
		||||
	hcd_reg1 host_type0;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	r = ((musb_core_config *)cfg)->regs;
 | 
			
		||||
	core = (musb_core_config *)cfg;
 | 
			
		||||
	r = core->regs;
 | 
			
		||||
 | 
			
		||||
	/* Set initial parameters */
 | 
			
		||||
	musb_setup_device(core, HCD_DEFAULT_EP, HCD_DEFAULT_ADDR);
 | 
			
		||||
 | 
			
		||||
	/* Set EP and device address to be used in this command */
 | 
			
		||||
	musb_set_state(core);
 | 
			
		||||
 | 
			
		||||
	/* Write reset bit and high speed negotiation wait for at least
 | 
			
		||||
	 * 20ms for reset, clear reset bit and wait for device */
 | 
			
		||||
@ -346,21 +382,37 @@ musb_reset_device(void * cfg)
 | 
			
		||||
	HCD_SET(power, MUSB_VAL_POWER_RESET | MUSB_VAL_POWER_HSEN);
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_POWER, power);
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		/* Sleep 25ms */
 | 
			
		||||
		struct timespec nanotm = {0, HCD_NANOSLEEP_MSEC(25)};
 | 
			
		||||
		nanosleep(&nanotm, NULL);
 | 
			
		||||
	}
 | 
			
		||||
	/* Sleep 25msec */
 | 
			
		||||
	hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(25));
 | 
			
		||||
 | 
			
		||||
	power = HCD_RD1(r, MUSB_REG_POWER);
 | 
			
		||||
	HCD_CLR(power, MUSB_VAL_POWER_RESET);
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_POWER, power);
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		/* Sleep 25ms */
 | 
			
		||||
		struct timespec nanotm = {0, HCD_NANOSLEEP_MSEC(25)};
 | 
			
		||||
		nanosleep(&nanotm, NULL);
 | 
			
		||||
	/* Sleep 25msec */
 | 
			
		||||
	hcd_os_nanosleep(HCD_NANOSLEEP_MSEC(25));
 | 
			
		||||
 | 
			
		||||
	/* High speed check */
 | 
			
		||||
	power = HCD_RD1(r, MUSB_REG_POWER);
 | 
			
		||||
 | 
			
		||||
	if (power & MUSB_VAL_POWER_HSMODE) {
 | 
			
		||||
		/* Set high-speed for EP0 */
 | 
			
		||||
		host_type0 = HCD_RD1(r, MUSB_REG_HOST_TYPE0);
 | 
			
		||||
		HCD_CLR(host_type0, MUSB_VAL_HOST_TYPE0_MASK);
 | 
			
		||||
		HCD_SET(host_type0, MUSB_VAL_HOST_TYPE0_HIGH_SPEED);
 | 
			
		||||
		HCD_WR1(r, MUSB_REG_HOST_TYPE0, host_type0);
 | 
			
		||||
 | 
			
		||||
		*speed = HCD_SPEED_HIGH;
 | 
			
		||||
 | 
			
		||||
		USB_DBG("High speed USB enabled");
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Only full-speed supported */
 | 
			
		||||
		USB_DBG("High speed USB disabled");
 | 
			
		||||
 | 
			
		||||
		*speed = HCD_SPEED_FULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -372,19 +424,21 @@ musb_setup_stage(void * cfg, hcd_ctrlrequest * setup)
 | 
			
		||||
{
 | 
			
		||||
	void * r;
 | 
			
		||||
	char * setup_byte;
 | 
			
		||||
	musb_core_config * core;
 | 
			
		||||
	hcd_reg2 host_csr0;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	r = ((musb_core_config *)cfg)->regs;
 | 
			
		||||
	core = (musb_core_config *)cfg;
 | 
			
		||||
	r = core->regs;
 | 
			
		||||
	setup_byte = (char*)setup;
 | 
			
		||||
 | 
			
		||||
	USB_ASSERT(0 == core->ep, "Only EP 0 can handle control transfers");
 | 
			
		||||
 | 
			
		||||
	/* Set EP and device address to be used in this command */
 | 
			
		||||
	musb_set_state((musb_core_config *)cfg);
 | 
			
		||||
	musb_set_state(core);
 | 
			
		||||
 | 
			
		||||
	/* TODO: check for ongoing transmission */
 | 
			
		||||
 | 
			
		||||
	/* Put USB setup data into corresponding FIFO */
 | 
			
		||||
	/* Put USB setup data into EP0 FIFO */
 | 
			
		||||
	HCD_WR4(r, MUSB_REG_FIFO0, HCD_8TO32(&setup_byte[0]));
 | 
			
		||||
	HCD_WR4(r, MUSB_REG_FIFO0, HCD_8TO32(&setup_byte[sizeof(hcd_reg4)]));
 | 
			
		||||
 | 
			
		||||
@ -399,6 +453,180 @@ musb_setup_stage(void * cfg, hcd_ctrlrequest * setup)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    musb_bulk_in_stage                                                     *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
void
 | 
			
		||||
musb_bulk_in_stage(void * cfg, hcd_bulkrequest * request)
 | 
			
		||||
{
 | 
			
		||||
	musb_core_config * core;
 | 
			
		||||
#if 0
 | 
			
		||||
	hcd_reg2 intrrxe;
 | 
			
		||||
#endif
 | 
			
		||||
	hcd_reg2 host_rxcsr;
 | 
			
		||||
	hcd_reg1 host_rxtype;
 | 
			
		||||
	void * r;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	core = (musb_core_config *)cfg;
 | 
			
		||||
	r = core->regs;
 | 
			
		||||
 | 
			
		||||
	USB_ASSERT(request->max_packet_size <= 1024, "Invalid wMaxPacketSize");
 | 
			
		||||
	USB_ASSERT((core->ep <= 15) && (core->ep > 0),
 | 
			
		||||
		"Invalid bulk EP supplied");
 | 
			
		||||
 | 
			
		||||
	/* Set EP and device address to be used in this command */
 | 
			
		||||
	musb_set_state(core);
 | 
			
		||||
 | 
			
		||||
	/* Evaluate RXTYPE */
 | 
			
		||||
	host_rxtype = MUSB_VAL_HOST_XXTYPE_BULK | core->ep;
 | 
			
		||||
 | 
			
		||||
	if (HCD_SPEED_HIGH == request->speed)
 | 
			
		||||
		host_rxtype |= MUSB_VAL_HOST_XXTYPE_HIGH_SPEED;
 | 
			
		||||
	else
 | 
			
		||||
		host_rxtype |= MUSB_VAL_HOST_XXTYPE_FULL_SPEED;
 | 
			
		||||
 | 
			
		||||
	/* Rewrite HOST_RXTYPE */
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_HOST_RXTYPE, host_rxtype);
 | 
			
		||||
 | 
			
		||||
	/* Rewrite RXMAXP */
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_RXMAXP, request->max_packet_size);
 | 
			
		||||
 | 
			
		||||
	/* Rewrite HOST_RXINTERVAL */
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_HOST_RXINTERVAL, MUSB_VAL_HOST_XXINTERVAL_DEFAULT);
 | 
			
		||||
 | 
			
		||||
	/* Not required in some MUSB implementations */
 | 
			
		||||
#if 0
 | 
			
		||||
	/* Enable this interrupt */
 | 
			
		||||
	intrrxe = HCD_RD2(r, MUSB_REG_INTRRXE);
 | 
			
		||||
	HCD_SET(intrrxe, HCD_BIT(core->ep));
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_INTRRXE, intrrxe);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* TODO: One reusable FIFO, no double buffering */
 | 
			
		||||
	/* TODO: With this, only one device can work at a time but it
 | 
			
		||||
	 * may be impossible to have MUSB work reasonably with multiple
 | 
			
		||||
	 * EP interrupts anyway */
 | 
			
		||||
	/* Assign FIFO */
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_RXFIFOADDR, MUSB_VAL_XXFIFOADDR_EP0_END);
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_RXFIFOSZ, MUSB_VAL_XXFIFOSZ_4096);
 | 
			
		||||
 | 
			
		||||
	/* TODO: decide which is better (or working at all when we use more
 | 
			
		||||
	 * than one transfer for bulk data in single device) */
 | 
			
		||||
#if 0
 | 
			
		||||
	/* Make controller reconfigure */
 | 
			
		||||
	host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
 | 
			
		||||
	HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_CLRDATATOG);
 | 
			
		||||
	HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_FLUSHFIFO);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
 | 
			
		||||
#else
 | 
			
		||||
	/* Reset and flush */
 | 
			
		||||
	host_rxcsr = 0;
 | 
			
		||||
	HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_CLRDATATOG);
 | 
			
		||||
	HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_FLUSHFIFO);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* Request packet */
 | 
			
		||||
	host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
 | 
			
		||||
	HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_REQPKT);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    musb_bulk_out_stage                                                    *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
void
 | 
			
		||||
musb_bulk_out_stage(void * cfg, hcd_bulkrequest * request)
 | 
			
		||||
{
 | 
			
		||||
	musb_core_config * core;
 | 
			
		||||
#if 0
 | 
			
		||||
	hcd_reg2 intrtxe;
 | 
			
		||||
#endif
 | 
			
		||||
	hcd_reg2 host_txcsr;
 | 
			
		||||
	hcd_reg1 host_txtype;
 | 
			
		||||
	void * r;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	core = (musb_core_config *)cfg;
 | 
			
		||||
	r = core->regs;
 | 
			
		||||
 | 
			
		||||
	USB_ASSERT(request->max_packet_size <= 1024, "Invalid wMaxPacketSize");
 | 
			
		||||
	USB_ASSERT((core->ep <= 15) && (core->ep > 0),
 | 
			
		||||
		"Invalid bulk EP supplied");
 | 
			
		||||
 | 
			
		||||
	/* Set EP and device address to be used in this command */
 | 
			
		||||
	musb_set_state(core);
 | 
			
		||||
 | 
			
		||||
	/* Evaluate TXTYPE */
 | 
			
		||||
	host_txtype = MUSB_VAL_HOST_XXTYPE_BULK | core->ep;
 | 
			
		||||
 | 
			
		||||
	if (HCD_SPEED_HIGH == request->speed)
 | 
			
		||||
		host_txtype |= MUSB_VAL_HOST_XXTYPE_HIGH_SPEED;
 | 
			
		||||
	else
 | 
			
		||||
		host_txtype |= MUSB_VAL_HOST_XXTYPE_FULL_SPEED;
 | 
			
		||||
 | 
			
		||||
	/* Rewrite HOST_TXTYPE */
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_HOST_TXTYPE, host_txtype);
 | 
			
		||||
 | 
			
		||||
	/* Rewrite TXMAXP */
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_TXMAXP, request->max_packet_size);
 | 
			
		||||
 | 
			
		||||
	/* Rewrite HOST_TXINTERVAL */
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_HOST_TXINTERVAL, MUSB_VAL_HOST_XXINTERVAL_DEFAULT);
 | 
			
		||||
 | 
			
		||||
	/* Not required in some MUSB implementations */
 | 
			
		||||
#if 0
 | 
			
		||||
	/* Enable this interrupt */
 | 
			
		||||
	intrtxe = HCD_RD2(r, MUSB_REG_INTRTXE);
 | 
			
		||||
	HCD_SET(intrtxe, HCD_BIT(core->ep));
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_INTRTXE, intrtxe);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* TODO: One reusable FIFO, no double buffering */
 | 
			
		||||
	/* TODO: With this, only one device can work at a time but it
 | 
			
		||||
	 * may be impossible to have MUSB work reasonably with multiple
 | 
			
		||||
	 * EP interrupts anyway */
 | 
			
		||||
	/* Assign FIFO */
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_TXFIFOADDR, MUSB_VAL_XXFIFOADDR_EP0_END);
 | 
			
		||||
	HCD_WR1(r, MUSB_REG_TXFIFOSZ, MUSB_VAL_XXFIFOSZ_4096);
 | 
			
		||||
 | 
			
		||||
	/* TODO: decide which is better (or working at all when we use more
 | 
			
		||||
	 * than one transfer for bulk data in single device) */
 | 
			
		||||
#if 0
 | 
			
		||||
	/* Make controller reconfigure */
 | 
			
		||||
	host_txcsr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
 | 
			
		||||
	HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_DMAMODE);
 | 
			
		||||
	HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_FRCDATATOG);
 | 
			
		||||
	HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_DMAEN);
 | 
			
		||||
	HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_MODE);
 | 
			
		||||
	HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_ISO);
 | 
			
		||||
	HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_AUTOSET);
 | 
			
		||||
	HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_CLRDATATOG);
 | 
			
		||||
	HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
 | 
			
		||||
#else
 | 
			
		||||
	/* Reset and flush */
 | 
			
		||||
	host_txcsr = 0;
 | 
			
		||||
	HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_MODE);
 | 
			
		||||
	HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_CLRDATATOG);
 | 
			
		||||
	HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* Put data in FIFO */
 | 
			
		||||
	musb_write_fifo(cfg, request->data, request->size, core->ep);
 | 
			
		||||
 | 
			
		||||
	/* Request packet */
 | 
			
		||||
	host_txcsr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
 | 
			
		||||
	HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_TXPKTRDY);
 | 
			
		||||
	HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    musb_in_data_stage                                                     *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
@ -435,9 +663,8 @@ musb_out_data_stage(void * cfg)
 | 
			
		||||
	/* Set EP and device address to be used in this command */
 | 
			
		||||
	musb_set_state((musb_core_config *)cfg);
 | 
			
		||||
 | 
			
		||||
	/* TODO: not needed for enumeration but will be needed later */
 | 
			
		||||
	((void)cfg);
 | 
			
		||||
	USB_MSG("NOT IMPLEMENTED");
 | 
			
		||||
	/* TODO: not needed for enumeration but may be needed later */
 | 
			
		||||
	USB_MSG("Setup packet's 'DATA OUT' stage not implemented");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -499,29 +726,29 @@ musb_out_status_stage(void * cfg)
 | 
			
		||||
 *    musb_read_data                                                         *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
int
 | 
			
		||||
musb_read_data(void * cfg, hcd_reg1 * buffer, int buffer_num)
 | 
			
		||||
musb_read_data(void * cfg, hcd_reg1 * buffer, int ep_num)
 | 
			
		||||
{
 | 
			
		||||
	int count0;
 | 
			
		||||
	int count;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
	/* Check if anything received at all */
 | 
			
		||||
	if (EXIT_SUCCESS != musb_check_rxpktrdy(cfg)) {
 | 
			
		||||
	if (EXIT_SUCCESS != musb_check_rxpktrdy(cfg, ep_num)) {
 | 
			
		||||
		USB_MSG("RXPKTRDY not set when receiving");
 | 
			
		||||
		return HCD_READ_ERR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Number of bytes received at EP0 */
 | 
			
		||||
	count0 = musb_get_count(cfg);
 | 
			
		||||
	/* Number of bytes received at any EP */
 | 
			
		||||
	count = musb_get_count(cfg);
 | 
			
		||||
 | 
			
		||||
	/* Read from given FIFO */
 | 
			
		||||
	if ((NULL != buffer) && (count0 > 0))
 | 
			
		||||
		musb_read_fifo(cfg, buffer, count0, buffer_num);
 | 
			
		||||
	if ((NULL != buffer) && (count > 0))
 | 
			
		||||
		musb_read_fifo(cfg, buffer, count, ep_num);
 | 
			
		||||
 | 
			
		||||
	/* Cleanup after reading */
 | 
			
		||||
	musb_in_stage_cleanup(cfg);
 | 
			
		||||
	musb_in_stage_cleanup(cfg, ep_num);
 | 
			
		||||
 | 
			
		||||
	return count0;
 | 
			
		||||
	return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -529,10 +756,10 @@ musb_read_data(void * cfg, hcd_reg1 * buffer, int buffer_num)
 | 
			
		||||
 *    musb_check_error                                                       *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
int
 | 
			
		||||
musb_check_error(void * cfg)
 | 
			
		||||
musb_check_error(void * cfg, hcd_transfer transfer, hcd_direction dir)
 | 
			
		||||
{
 | 
			
		||||
	void * r;
 | 
			
		||||
	hcd_reg2 host_csr0;
 | 
			
		||||
	hcd_reg2 host_csr;
 | 
			
		||||
 | 
			
		||||
	DEBUG_DUMP;
 | 
			
		||||
 | 
			
		||||
@ -541,30 +768,95 @@ musb_check_error(void * cfg)
 | 
			
		||||
	/* Set EP and device address to be used in this command */
 | 
			
		||||
	musb_set_state((musb_core_config *)cfg);
 | 
			
		||||
 | 
			
		||||
	/* Get control status register for EP 0 */
 | 
			
		||||
	host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0);
 | 
			
		||||
	/* TODO: In MUSB only EP0 is allowed to handle control transfers
 | 
			
		||||
	 * so there is no EP checking in this function */
 | 
			
		||||
	if (HCD_TRANSFER_CONTROL == transfer) {
 | 
			
		||||
		/* Get control status register */
 | 
			
		||||
		host_csr = HCD_RD2(r, MUSB_REG_HOST_CSR0);
 | 
			
		||||
 | 
			
		||||
	/* Check for common errors */
 | 
			
		||||
	if (host_csr0 & MUSB_VAL_HOST_CSR0_ERROR) {
 | 
			
		||||
		USB_MSG("HOST_CSR0 ERROR: %04X", host_csr0);
 | 
			
		||||
		HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_ERROR);
 | 
			
		||||
		HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
		/* Check for common errors */
 | 
			
		||||
		if (host_csr & MUSB_VAL_HOST_CSR0_ERROR) {
 | 
			
		||||
			USB_MSG("HOST_CSR0 ERROR: %04X", host_csr);
 | 
			
		||||
			HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_ERROR);
 | 
			
		||||
			HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr);
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (host_csr & MUSB_VAL_HOST_CSR0_RXSTALL) {
 | 
			
		||||
			USB_MSG("HOST_CSR0 STALL: %04X", host_csr);
 | 
			
		||||
			HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_RXSTALL);
 | 
			
		||||
			HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr);
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (host_csr & MUSB_VAL_HOST_CSR0_NAK_TIMEOUT) {
 | 
			
		||||
			USB_MSG("HOST_CSR0 NAK_TIMEOUT: %04X", host_csr);
 | 
			
		||||
			HCD_CLR(host_csr, MUSB_VAL_HOST_CSR0_NAK_TIMEOUT);
 | 
			
		||||
			HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr);
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return EXIT_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (host_csr0 & MUSB_VAL_HOST_CSR0_RXSTALL) {
 | 
			
		||||
		USB_MSG("HOST_CSR0 STALL: %04X", host_csr0);
 | 
			
		||||
		HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_RXSTALL);
 | 
			
		||||
		HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	if ((HCD_TRANSFER_BULK == transfer) && (HCD_DIRECTION_OUT == dir)) {
 | 
			
		||||
		/* Get RX status register */
 | 
			
		||||
		host_csr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
 | 
			
		||||
 | 
			
		||||
		/* Check for common errors */
 | 
			
		||||
		if (host_csr & MUSB_VAL_HOST_TXCSR_ERROR) {
 | 
			
		||||
			USB_MSG("HOST_TXCSR ERROR: %04X", host_csr);
 | 
			
		||||
			HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_ERROR);
 | 
			
		||||
			HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (host_csr & MUSB_VAL_HOST_TXCSR_RXSTALL) {
 | 
			
		||||
			USB_MSG("HOST_TXCSR STALL: %04X", host_csr);
 | 
			
		||||
			HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_RXSTALL);
 | 
			
		||||
			HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (host_csr & MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT) {
 | 
			
		||||
			USB_MSG("HOST_TXCSR NAK_TIMEOUT: %04X", host_csr);
 | 
			
		||||
			HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT);
 | 
			
		||||
			HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return EXIT_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (host_csr0 & MUSB_VAL_HOST_CSR0_NAK_TIMEOUT) {
 | 
			
		||||
		USB_MSG("HOST_CSR0 NAK_TIMEOUT: %04X", host_csr0);
 | 
			
		||||
		HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_NAK_TIMEOUT);
 | 
			
		||||
		HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
 | 
			
		||||
		return EXIT_FAILURE;
 | 
			
		||||
	if ((HCD_TRANSFER_BULK == transfer) && (HCD_DIRECTION_IN == dir)) {
 | 
			
		||||
		/* Get RX status register */
 | 
			
		||||
		host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
 | 
			
		||||
 | 
			
		||||
		/* Check for common errors */
 | 
			
		||||
		if (host_csr & MUSB_VAL_HOST_RXCSR_ERROR) {
 | 
			
		||||
			USB_MSG("HOST_RXCSR ERROR: %04X", host_csr);
 | 
			
		||||
			HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_ERROR);
 | 
			
		||||
			HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (host_csr & MUSB_VAL_HOST_RXCSR_RXSTALL) {
 | 
			
		||||
			USB_MSG("HOST_RXCSR STALL: %04X", host_csr);
 | 
			
		||||
			HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_RXSTALL);
 | 
			
		||||
			HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (host_csr & MUSB_VAL_HOST_RXCSR_NAKTIMEOUT) {
 | 
			
		||||
			USB_MSG("HOST_RXCSR NAK_TIMEOUT: %04X", host_csr);
 | 
			
		||||
			HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_NAKTIMEOUT);
 | 
			
		||||
			HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
 | 
			
		||||
			return EXIT_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return EXIT_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return EXIT_SUCCESS;
 | 
			
		||||
	USB_MSG("Invalid USB transfer 0x%X:0x%X", (int)transfer, (int)dir);
 | 
			
		||||
	return EXIT_FAILURE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -29,19 +29,20 @@ musb_core_config;
 | 
			
		||||
/* Only to be used outside generic HCD code */
 | 
			
		||||
void musb_core_start(void *);
 | 
			
		||||
void musb_core_stop(void *);
 | 
			
		||||
void musb_ep0_config(void *);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* For HCD interface */
 | 
			
		||||
void musb_setup_device(void *, hcd_reg1, hcd_reg1);
 | 
			
		||||
void musb_reset_device(void *);
 | 
			
		||||
int musb_reset_device(void *, hcd_speed *);
 | 
			
		||||
void musb_setup_stage(void *, hcd_ctrlrequest *);
 | 
			
		||||
void musb_bulk_in_stage(void *, hcd_bulkrequest *);
 | 
			
		||||
void musb_bulk_out_stage(void *, hcd_bulkrequest *);
 | 
			
		||||
void musb_in_data_stage(void *);
 | 
			
		||||
void musb_out_data_stage(void *);
 | 
			
		||||
void musb_in_status_stage(void *);
 | 
			
		||||
void musb_out_status_stage(void *);
 | 
			
		||||
int musb_read_data(void *, hcd_reg1 *, int);
 | 
			
		||||
int musb_check_error(void *);
 | 
			
		||||
int musb_check_error(void *, hcd_transfer, hcd_direction);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* !_MUSB_CORE_H_ */
 | 
			
		||||
 | 
			
		||||
@ -33,16 +33,15 @@
 | 
			
		||||
#define MUSB_REG_HOST_TXCSR				MUSB_REG_PERI_CSR0
 | 
			
		||||
#define MUSB_REG_RXMAXP				0x14u
 | 
			
		||||
#define MUSB_REG_PERI_RXCSR			0x16u
 | 
			
		||||
#define MUSB_REG_HOST_RXCSR				MUSB_PERI_RXCSR
 | 
			
		||||
#define MUSB_REG_HOST_RXCSR				MUSB_REG_PERI_RXCSR
 | 
			
		||||
#define MUSB_REG_COUNT0				0x18u
 | 
			
		||||
#define MUSB_REG_RXCOUNT				MUSB_COUNT0
 | 
			
		||||
#define MUSB_REG_RXCOUNT				MUSB_REG_COUNT0
 | 
			
		||||
#define MUSB_REG_HOST_TYPE0			0x1Au
 | 
			
		||||
#define MUSB_REG_HOST_TXTYPE				MUSB_HOST_TYPE0
 | 
			
		||||
#define MUSB_REG_HOST_TXTYPE				MUSB_REG_HOST_TYPE0
 | 
			
		||||
#define MUSB_REG_HOST_NAKLIMIT0			0x1Bu
 | 
			
		||||
#define MUSB_REG_HOST_TXINTERVAL			MUSB_HOST_NAKLIMIT0
 | 
			
		||||
#define MUSB_REG_HOST_TXINTERVAL			MUSB_REG_HOST_NAKLIMIT0
 | 
			
		||||
#define MUSB_REG_HOST_RXTYPE			0x1Cu
 | 
			
		||||
#define MUSB_REG_HOST_RXINTERVAL		0x1Du
 | 
			
		||||
#define MUSB_REG_CONFIGDATA			0x1Fu
 | 
			
		||||
 | 
			
		||||
#define MUSB_REG_FIFO0				0x20u
 | 
			
		||||
#define MUSB_REG_FIFO1				0x24u
 | 
			
		||||
@ -57,12 +56,16 @@
 | 
			
		||||
#define MUSB_REG_TXFIFOADDR			0x64u
 | 
			
		||||
#define MUSB_REG_RXFIFOADDR			0x66u
 | 
			
		||||
 | 
			
		||||
#define MUSB_REG_TXFUNCADDR			0x80u
 | 
			
		||||
#define MUSB_REG_TXHUBADDR			0x82u
 | 
			
		||||
#define MUSB_REG_TXHUBPORT			0x83u
 | 
			
		||||
#define MUSB_REG_RXFUNCADDR			0x84u
 | 
			
		||||
#define MUSB_REG_RXHUBADDR			0x86u
 | 
			
		||||
#define MUSB_REG_RXHUBPORT			0x87u
 | 
			
		||||
#define MUSB_REG_EP_CONFIG_BASE			0x80u
 | 
			
		||||
#define MUSB_REG_TXFUNCADDR			0x00u
 | 
			
		||||
#define MUSB_REG_TXHUBADDR			0x02u
 | 
			
		||||
#define MUSB_REG_TXHUBPORT			0x03u
 | 
			
		||||
#define MUSB_REG_RXFUNCADDR			0x04u
 | 
			
		||||
#define MUSB_REG_RXHUBADDR			0x06u
 | 
			
		||||
#define MUSB_REG_RXHUBPORT			0x07u
 | 
			
		||||
#define MUSB_REG_EP_CONFIG_LEN			0x08u
 | 
			
		||||
#define MUSB_REG_CONFIG(ep,reg)			\
 | 
			
		||||
	(MUSB_REG_EP_CONFIG_BASE + (MUSB_REG_EP_CONFIG_LEN * (ep)) + (reg))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
@ -123,4 +126,68 @@
 | 
			
		||||
#define MUSB_VAL_HOST_CSR0_NAK_TIMEOUT		HCD_BIT(7)
 | 
			
		||||
#define MUSB_VAL_HOST_CSR0_FLUSHFIFO		HCD_BIT(8)
 | 
			
		||||
 | 
			
		||||
/* HOST_RXTYPE/HOST_TXTYPE */
 | 
			
		||||
#define MUSB_VAL_HOST_XXTYPE_SPEED_MASK		(HCD_BIT(6) | HCD_BIT(7))
 | 
			
		||||
#define MUSB_VAL_HOST_XXTYPE_HIGH_SPEED		HCD_BIT(6)
 | 
			
		||||
#define MUSB_VAL_HOST_XXTYPE_FULL_SPEED		HCD_BIT(7)
 | 
			
		||||
#define MUSB_VAL_HOST_XXTYPE_LOW_SPEED		(HCD_BIT(6) | HCD_BIT(7))
 | 
			
		||||
#define MUSB_VAL_HOST_XXTYPE_PROT_MASK		(HCD_BIT(4) | HCD_BIT(5))
 | 
			
		||||
#define MUSB_VAL_HOST_XXTYPE_ISOCHRONOUS	HCD_BIT(4)
 | 
			
		||||
#define MUSB_VAL_HOST_XXTYPE_BULK		HCD_BIT(5)
 | 
			
		||||
#define MUSB_VAL_HOST_XXTYPE_INTERRUPT		(HCD_BIT(4) | HCD_BIT(5))
 | 
			
		||||
#define MUSB_VAL_HOST_XXTYPE_RENDPN_MASK	(HCD_BIT(0) |		\
 | 
			
		||||
						 HCD_BIT(1) |		\
 | 
			
		||||
						 HCD_BIT(2) |		\
 | 
			
		||||
						 HCD_BIT(3))
 | 
			
		||||
 | 
			
		||||
/* HOST_RXINTERVAL/HOST_TXINTERVAL */
 | 
			
		||||
/* TODO: Default NAK limit */
 | 
			
		||||
#define MUSB_VAL_HOST_XXINTERVAL_DEFAULT	0x10u
 | 
			
		||||
 | 
			
		||||
/* HOST_RXCSR */
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_RXPKTRDY		HCD_BIT(0)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_FIFOFULL		HCD_BIT(1)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_ERROR		HCD_BIT(2)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_NAKTIMEOUT		HCD_BIT(3)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_FLUSHFIFO		HCD_BIT(4)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_REQPKT		HCD_BIT(5)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_RXSTALL		HCD_BIT(6)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_CLRDATATOG		HCD_BIT(7)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_DATATOG		HCD_BIT(9)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_DATATOGWREN		HCD_BIT(10)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_DISNYET		HCD_BIT(12)
 | 
			
		||||
#define MUSB_VAL_HOST_RXCSR_DMAEN		HCD_BIT(13)
 | 
			
		||||
 | 
			
		||||
/* HOST_TXCSR */
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_TXPKTRDY		HCD_BIT(0)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_FIFONOTEMPTY	HCD_BIT(1)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_ERROR		HCD_BIT(2)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_FLUSHFIFO		HCD_BIT(3)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_SETUPPKT		HCD_BIT(4)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_RXSTALL		HCD_BIT(5)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_CLRDATATOG		HCD_BIT(6)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT		HCD_BIT(7)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_DATATOG		HCD_BIT(8)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_DATATOGWREN		HCD_BIT(9)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_DMAMODE		HCD_BIT(10)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_FRCDATATOG		HCD_BIT(11)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_DMAEN		HCD_BIT(12)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_MODE		HCD_BIT(13)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_ISO			HCD_BIT(14)
 | 
			
		||||
#define MUSB_VAL_HOST_TXCSR_AUTOSET		HCD_BIT(15)
 | 
			
		||||
 | 
			
		||||
/* RXFIFOADDR/TXFIFOADDR */
 | 
			
		||||
#define MUSB_VAL_XXFIFOADDR_EP0_END		0x08u
 | 
			
		||||
 | 
			
		||||
/* RXFIFOSZ/TXFIFOSZ */
 | 
			
		||||
#define MUSB_VAL_XXFIFOSZ_16			0x01u
 | 
			
		||||
#define MUSB_VAL_XXFIFOSZ_32			0x02u
 | 
			
		||||
#define MUSB_VAL_XXFIFOSZ_64			0x03u
 | 
			
		||||
#define MUSB_VAL_XXFIFOSZ_128			0x04u
 | 
			
		||||
#define MUSB_VAL_XXFIFOSZ_256			0x05u
 | 
			
		||||
#define MUSB_VAL_XXFIFOSZ_512			0x06u
 | 
			
		||||
#define MUSB_VAL_XXFIFOSZ_1024			0x07u
 | 
			
		||||
#define MUSB_VAL_XXFIFOSZ_2048			0x08u
 | 
			
		||||
#define MUSB_VAL_XXFIFOSZ_4096			0x09u
 | 
			
		||||
 | 
			
		||||
#endif /* !_MUSB_REGS_H_ */
 | 
			
		||||
 | 
			
		||||
@ -62,7 +62,6 @@ typedef unsigned char				hcd_reg1;
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    USB descriptor types                                                   *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
typedef struct usb_ctrlrequest			hcd_ctrlrequest;
 | 
			
		||||
typedef usb_descriptor_t			hcd_descriptor;
 | 
			
		||||
typedef usb_device_descriptor_t			hcd_device_descriptor;
 | 
			
		||||
typedef usb_config_descriptor_t			hcd_config_descriptor;
 | 
			
		||||
@ -114,13 +113,21 @@ typedef enum {
 | 
			
		||||
}
 | 
			
		||||
hcd_state;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
 | 
			
		||||
	HCD_SPEED_LOW,
 | 
			
		||||
	HCD_SPEED_FULL,
 | 
			
		||||
	HCD_SPEED_HIGH,
 | 
			
		||||
}
 | 
			
		||||
hcd_speed;
 | 
			
		||||
 | 
			
		||||
/* Largest value that can be transfered by this driver at a time
 | 
			
		||||
 * see MAXPAYLOAD in TXMAXP/RXMAXP */
 | 
			
		||||
#define MAX_WTOTALLENGTH 1024
 | 
			
		||||
 | 
			
		||||
typedef struct hcd_device_state {
 | 
			
		||||
 | 
			
		||||
	hcd_driver_state * driver;
 | 
			
		||||
	hcd_driver_state * driver;	/* Specific HCD driver object */
 | 
			
		||||
	hcd_thread * thread;
 | 
			
		||||
	hcd_lock * lock;
 | 
			
		||||
	hcd_urb * urb;
 | 
			
		||||
@ -129,11 +136,13 @@ typedef struct hcd_device_state {
 | 
			
		||||
	hcd_device_descriptor device_desc;
 | 
			
		||||
	hcd_configuration config_tree;
 | 
			
		||||
	hcd_reg1 max_packet_size;
 | 
			
		||||
 | 
			
		||||
	hcd_speed speed;
 | 
			
		||||
	hcd_state state;
 | 
			
		||||
	int address;
 | 
			
		||||
 | 
			
		||||
	/* Number of bytes received/transmitted in last transfer */
 | 
			
		||||
	int data_len;
 | 
			
		||||
 | 
			
		||||
	/* TODO: forcefully align buffer to make things clear? */
 | 
			
		||||
	/* Buffer for each device to hold transfered data */
 | 
			
		||||
	hcd_reg1 buffer[MAX_WTOTALLENGTH];
 | 
			
		||||
@ -141,12 +150,68 @@ typedef struct hcd_device_state {
 | 
			
		||||
hcd_device_state;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    HCD transfer requests                                                  *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
struct hcd_bulkrequest {
 | 
			
		||||
 | 
			
		||||
	char * data;
 | 
			
		||||
	int size;
 | 
			
		||||
	int endpoint;
 | 
			
		||||
	unsigned int max_packet_size;
 | 
			
		||||
	hcd_speed speed;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct usb_ctrlrequest		hcd_ctrlrequest;
 | 
			
		||||
typedef struct hcd_bulkrequest		hcd_bulkrequest;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    HCD event handling                                                     *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
/* Possible USB transfer types */
 | 
			
		||||
typedef enum {
 | 
			
		||||
 | 
			
		||||
	HCD_TRANSFER_CONTROL		= UE_CONTROL,
 | 
			
		||||
	HCD_TRANSFER_ISOCHRONOUS	= UE_ISOCHRONOUS,
 | 
			
		||||
	HCD_TRANSFER_BULK		= UE_BULK,
 | 
			
		||||
	HCD_TRANSFER_INTERRUPT		= UE_INTERRUPT
 | 
			
		||||
}
 | 
			
		||||
hcd_transfer;
 | 
			
		||||
 | 
			
		||||
/* Possible USB transfer directions */
 | 
			
		||||
typedef enum {
 | 
			
		||||
 | 
			
		||||
	HCD_DIRECTION_OUT		= 0,
 | 
			
		||||
	HCD_DIRECTION_IN		= 1,
 | 
			
		||||
	HCD_DIRECTION_UNUSED		= 0xFF
 | 
			
		||||
}
 | 
			
		||||
hcd_direction;
 | 
			
		||||
 | 
			
		||||
/* Possible asynchronous HCD events */
 | 
			
		||||
typedef enum {
 | 
			
		||||
 | 
			
		||||
	HCD_EVENT_CONNECTED,
 | 
			
		||||
	HCD_EVENT_DISCONNECTED,
 | 
			
		||||
	HCD_EVENT_ENDPOINT,
 | 
			
		||||
	HCD_EVENT_URB
 | 
			
		||||
}
 | 
			
		||||
hcd_event;
 | 
			
		||||
 | 
			
		||||
/* EP event constants */
 | 
			
		||||
#define HCD_NO_ENDPOINT			-1
 | 
			
		||||
#define HCD_ENDPOINT_0			0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    Other definitions                                                      *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
#define HCD_NANOSLEEP_SEC(sec)		((sec)  * 1000000000)
 | 
			
		||||
#define HCD_NANOSLEEP_MSEC(msec)	((msec) * 1000000)
 | 
			
		||||
#define HCD_NANOSLEEP_USEC(usec)	((usec) * 1000)
 | 
			
		||||
#define HCD_MILI			1000
 | 
			
		||||
#define HCD_MICRO			1000000
 | 
			
		||||
#define HCD_NANO			1000000000
 | 
			
		||||
#define HCD_NANOSLEEP_SEC(sec)		((sec)  * HCD_NANO)
 | 
			
		||||
#define HCD_NANOSLEEP_MSEC(msec)	((msec) * HCD_MICRO)
 | 
			
		||||
#define HCD_NANOSLEEP_USEC(usec)	((usec) * HCD_MILI)
 | 
			
		||||
 | 
			
		||||
/* Default USB communication parameters */
 | 
			
		||||
#define HCD_DEFAULT_EP		0x00
 | 
			
		||||
@ -184,6 +249,9 @@ int hcd_os_clkconf(unsigned long, unsigned long, unsigned long);
 | 
			
		||||
/* Release clocking */
 | 
			
		||||
int hcd_os_clkconf_release(void);
 | 
			
		||||
 | 
			
		||||
/* OS's sleep wrapper */
 | 
			
		||||
void hcd_os_nanosleep(int);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    Device handling calls                                                  *
 | 
			
		||||
@ -195,7 +263,7 @@ int hcd_connect_device(hcd_device_state *, hcd_thread_function);
 | 
			
		||||
void hcd_disconnect_device(hcd_device_state *);
 | 
			
		||||
 | 
			
		||||
/* Locks device thread until 'hcd_device_continue' */
 | 
			
		||||
void hcd_device_wait(hcd_device_state *);
 | 
			
		||||
void hcd_device_wait(hcd_device_state *, hcd_event, int);
 | 
			
		||||
 | 
			
		||||
/* Unlocks device thread halted by 'hcd_device_wait' */
 | 
			
		||||
void hcd_device_continue(hcd_device_state *);
 | 
			
		||||
@ -210,5 +278,8 @@ int hcd_buffer_to_tree(hcd_reg1 *, int, hcd_configuration *);
 | 
			
		||||
/* Frees descriptor tree */
 | 
			
		||||
void hcd_tree_cleanup(hcd_configuration *);
 | 
			
		||||
 | 
			
		||||
/* Find EP in a tree */
 | 
			
		||||
hcd_endpoint * hcd_tree_find_ep(hcd_configuration *, int);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* !_HCD_COMMON_H_ */
 | 
			
		||||
 | 
			
		||||
@ -11,30 +11,10 @@
 | 
			
		||||
#include <usb/hcd_common.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    HCD event handling types                                               *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
/* Possible HCD events */
 | 
			
		||||
typedef enum {
 | 
			
		||||
 | 
			
		||||
	HCD_EVENT_CONNECTED,
 | 
			
		||||
	HCD_EVENT_DISCONNECTED,
 | 
			
		||||
	HCD_EVENT_ENDPOINT
 | 
			
		||||
}
 | 
			
		||||
hcd_event;
 | 
			
		||||
 | 
			
		||||
/* Possible HCD sub-events */
 | 
			
		||||
typedef enum {
 | 
			
		||||
 | 
			
		||||
	HCD_SUBEVENT_NONE,
 | 
			
		||||
	HCD_SUBEVENT_EP0,
 | 
			
		||||
}
 | 
			
		||||
hcd_subevent;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
 *    HCD additional defines                                                 *
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
/* Can be returned by 'read_data' to indicate error */
 | 
			
		||||
#define HCD_READ_ERR -1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -43,22 +23,26 @@ hcd_subevent;
 | 
			
		||||
 *===========================================================================*/
 | 
			
		||||
struct hcd_driver_state {
 | 
			
		||||
	/* Standard USB controller procedures */
 | 
			
		||||
	void		(*setup_device)		(void *, hcd_reg1, hcd_reg1);
 | 
			
		||||
	void		(*reset_device)		(void *);
 | 
			
		||||
	void		(*setup_stage)		(void *, hcd_ctrlrequest *);
 | 
			
		||||
	void		(*in_data_stage)	(void *);
 | 
			
		||||
	void		(*out_data_stage)	(void *);
 | 
			
		||||
	void		(*in_status_stage)	(void *);
 | 
			
		||||
	void		(*out_status_stage)	(void *);
 | 
			
		||||
	int		(*read_data)		(void *, hcd_reg1 *, int);
 | 
			
		||||
	int		(*check_error)		(void *);
 | 
			
		||||
	void	(*setup_device)		(void *, hcd_reg1, hcd_reg1);
 | 
			
		||||
	int	(*reset_device)		(void *, hcd_speed *);
 | 
			
		||||
	void	(*setup_stage)		(void *, hcd_ctrlrequest *);
 | 
			
		||||
	void	(*bulk_in_stage)	(void *, hcd_bulkrequest *);
 | 
			
		||||
	void	(*bulk_out_stage)	(void *, hcd_bulkrequest *);
 | 
			
		||||
	void	(*in_data_stage)	(void *);
 | 
			
		||||
	void	(*out_data_stage)	(void *);
 | 
			
		||||
	void	(*in_status_stage)	(void *);
 | 
			
		||||
	void	(*out_status_stage)	(void *);
 | 
			
		||||
	int	(*read_data)		(void *, hcd_reg1 *, int);
 | 
			
		||||
	int	(*check_error)		(void *, hcd_transfer, hcd_direction);
 | 
			
		||||
 | 
			
		||||
	/* Controller's private data (like mapped registers) */
 | 
			
		||||
	void *		private_data;
 | 
			
		||||
 | 
			
		||||
	/* Current state to be handled by driver */
 | 
			
		||||
	hcd_event	event;
 | 
			
		||||
	hcd_subevent	subevent;
 | 
			
		||||
	hcd_event	current_event;
 | 
			
		||||
	int		current_endpoint;
 | 
			
		||||
	hcd_event	expected_event;
 | 
			
		||||
	int		expected_endpoint;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user