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