#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 */
/* TODO: No headers for these... */
extern void ddekit_minix_wait_exit(void); /* dde.c */
-extern void ddekit_usb_server_init(void); /* usb_server.c */
/*===========================================================================*
int ret_val;
USB_MSG("Starting USBD");
+ USB_DBG("Built: %s %s", __DATE__, __TIME__);
/* Basic SEF,DDE,... initialization */
usbd_init();
* 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>
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];
/* 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(
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);
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");
/* 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");
}
}
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)) {
}
/* 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)) {
/* 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;
}
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;
}
static int
hcd_handle_urb(hcd_device_state * this_device)
{
+ hcd_urb * urb;
+ int transfer_status;
+
+ DEBUG_DUMP;
+
+ transfer_status = EXIT_FAILURE;
+ urb = this_device->urb;
+
+ USB_ASSERT(NULL != urb, "NULL URB given");
+ /* TODO: One device only */
+ USB_ASSERT((void *)this_device != (void *)urb->dev,
+ "Unknown device for URB");
+
+ 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;
- USB_ASSERT(NULL != this_device->urb, "NULL URB received");
+ urb = this_device->urb;
- /* TODO: URB handling will be here */
+ /* Assume bad values unless something different occurs later */
+ urb->status = EINVAL;
- /* TODO: call completion */
- /* hcd_completion_cb */
+ /* 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;
}
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... */
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 */
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 {
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 */
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;
+}
*/
#include <string.h> /* memset... */
+#include <time.h> /* nanosleep */
#include <sys/mman.h> /* Physical to virtual memory mapping */
#include <minix/syslib.h> /* sys_privctl */
#include <usb/hcd_common.h>
+#include <usb/hcd_interface.h>
#include <usb/usb_common.h>
}
+/*===========================================================================*
+ * 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 *
*===========================================================================*/
* 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);
}
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);
}
/* 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++))
}
+/*===========================================================================*
+ * 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 *
*===========================================================================*/
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);
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;
#include <ddekit/usb.h>
#include <usb/hcd_ddekit.h>
+#include <usb/hcd_interface.h>
#include <usb/usb_common.h>
{
static const char mfg[] = "UNKNOWN";
DEBUG_DUMP;
- /* TODO: UNUSED won't work */
+ /* TODO: UNUSED for argument won't work */
((void)ddev);
return (char *)mfg;
}
{
static const char prod[] = "UNKNOWN";
DEBUG_DUMP;
- /* TODO: UNUSED won't work */
+ /* TODO: UNUSED for argument won't work */
((void)ddev);
return (char *)prod;
}
{
static const char serial[] = "UNKNOWN";
DEBUG_DUMP;
- /* TODO: UNUSED won't work */
+ /* TODO: UNUSED for argument won't work */
((void)ddev);
return (char *)serial;
}
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;
{
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;
}
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;
}
*/
#include <string.h> /* memset */
-#include <time.h> /* nanosleep */
#include <usb/hcd_common.h>
#include <usb/hcd_platforms.h>
/*===========================================================================*
* 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
#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
#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)
#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))
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);
/* 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;
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,
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;
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,
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;
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");
}
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 */
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
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));
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;
}
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;
}
}
+/*===========================================================================*
+ * 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 *
*===========================================================================*/
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
}
*/
#include <string.h> /* memcpy */
-#include <time.h> /* nanosleep */
#include <usb/hcd_common.h>
#include <usb/hcd_interface.h>
#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);
/*===========================================================================*
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);
}
* 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;
/* 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;
}
* 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);
}
* 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;
/* 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);
-
- /* Clear RXPKTRDY to signal receive completion */
- HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_RXPKTRDY);
- HCD_WR2(r, MUSB_REG_HOST_CSR0, 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_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);
+ }
}
* 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;
+
+ /* 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);
+ }
+ }
- /* Read full words from MUSB FIFO */
+ 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;
+/*===========================================================================*
+ * musb_write_fifo *
+ *===========================================================================*/
+static void
+musb_write_fifo(void * cfg, void * input, int size, int fifo_num)
+{
+ void * r;
- /* Read words from FIFO into copy_buf */
- for (idx = 0; idx < limit; idx += sizeof(*word))
- *word++ = HCD_RD4(r, fifo_addr);
+ hcd_reg1 * input_b;
+ hcd_reg4 * input_w;
- /* Copy and shift */
- memcpy(output, copy_buf, limit);
- output += limit;
- size -= limit;
+ 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--;
}
}
}
-/*===========================================================================*
- * 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 *
/*===========================================================================*
* 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 */
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;
}
{
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;
- /* Set EP and device address to be used in this command */
- musb_set_state((musb_core_config *)cfg);
+ USB_ASSERT(0 == core->ep, "Only EP 0 can handle control transfers");
- /* TODO: check for ongoing transmission */
+ /* Set EP and device address to be used in this command */
+ musb_set_state(core);
- /* 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)]));
}
+/*===========================================================================*
+ * 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 *
*===========================================================================*/
/* 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");
}
* 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;
}
* 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;
/* 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_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;
+ }
- /* 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;
+ 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;
}
/* 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_ */
#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
#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))
/*===========================================================================*
#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_ */
/*===========================================================================*
* 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;
}
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;
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];
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
/* Release clocking */
int hcd_os_clkconf_release(void);
+/* OS's sleep wrapper */
+void hcd_os_nanosleep(int);
+
/*===========================================================================*
* Device handling calls *
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 *);
/* 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_ */
#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
*===========================================================================*/
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;
};