arm:adding the usbd source code.
Change-Id: Ia3c50a8c5e11bf20100354de266913112cc236f9 http://gerrit.minix3.org/#/c/2689/
This commit is contained in:
parent
3553b1a2f5
commit
ed3391fd23
19 changed files with 3438 additions and 0 deletions
11
drivers/usbd/Makefile
Executable file
11
drivers/usbd/Makefile
Executable file
|
@ -0,0 +1,11 @@
|
||||||
|
# Makefile for usb host controllers
|
||||||
|
|
||||||
|
.if ${MACHINE_ARCH} == "earm"
|
||||||
|
|
||||||
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
|
SUBDIR= .WAIT base/earm
|
||||||
|
|
||||||
|
.include <bsd.subdir.mk>
|
||||||
|
|
||||||
|
.endif
|
16
drivers/usbd/README.txt
Executable file
16
drivers/usbd/README.txt
Executable file
|
@ -0,0 +1,16 @@
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
* INFORMATION: *
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
README file for "USBD" USB host controller driver.
|
||||||
|
|
||||||
|
created march-may 2014, JPEmbedded (info@jpembedded.eu)
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
* KNOWN LIMITATIONS: *
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
- Only first configuration can be selected for attached device
|
||||||
|
- Only one device can be handled at a time, no hub functionality
|
||||||
|
- DDEKit does not implement resource deallocation for corresponding thread
|
||||||
|
creation (see ddekit_thread_terminate, ddekit_thread_create) thus resources
|
||||||
|
are spilled
|
||||||
|
- Driver assumes that there is no preemption for DDEKit threading
|
19
drivers/usbd/base/earm/Makefile
Executable file
19
drivers/usbd/base/earm/Makefile
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
#
|
||||||
|
# Makefile for the EARM USBD
|
||||||
|
#
|
||||||
|
|
||||||
|
PROG= usbd
|
||||||
|
SRCS= usbd.c usbd_earm.c hcd.c hcd_common.c hcd_ddekit.c musb_am335x.c musb_core.c
|
||||||
|
|
||||||
|
.PATH: ${.CURDIR}/../ ${.CURDIR}/../../hcd ${.CURDIR}/../../hcd/musb
|
||||||
|
|
||||||
|
CPPFLAGS+= -I${.CURDIR}/../../include
|
||||||
|
|
||||||
|
DPADD+= ${LIBDDEKIT} ${LIBDDEKIT_USB_SERVER} ${LIBDEVMAN} ${LIBUSB} ${LIBMINC} ${LIBCLKCONF}
|
||||||
|
LDADD+= -lddekit -lddekit_usb_server -ldevman -lusb -lminc -lclkconf
|
||||||
|
|
||||||
|
MAN=
|
||||||
|
|
||||||
|
BINDIR?= /usr/sbin
|
||||||
|
|
||||||
|
.include <minix.service.mk>
|
59
drivers/usbd/base/earm/usbd_earm.c
Executable file
59
drivers/usbd/base/earm/usbd_earm.c
Executable file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* EARM USBD setup
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <minix/board.h>
|
||||||
|
#include <minix/syslib.h>
|
||||||
|
|
||||||
|
#include <usb/hcd_platforms.h>
|
||||||
|
#include <usb/usb_common.h>
|
||||||
|
#include <usb/usbd_interface.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usbd_init_hcd *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
usbd_init_hcd(void)
|
||||||
|
{
|
||||||
|
/* More specific platform type than just EARM */
|
||||||
|
static struct machine platform;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
if (sys_getmachine(&platform)) {
|
||||||
|
USB_MSG("Getting machine type, failed");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOARD_IS_BB(platform.board_id)) {
|
||||||
|
USB_MSG("Using AM335x driver");
|
||||||
|
return musb_am335x_init();
|
||||||
|
} else {
|
||||||
|
USB_MSG("Only AM335x driver available");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usbd_deinit_hcd *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
usbd_deinit_hcd(void)
|
||||||
|
{
|
||||||
|
/* More specific platform type than just EARM */
|
||||||
|
static struct machine platform;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
if (sys_getmachine(&platform)) {
|
||||||
|
USB_MSG("Getting machine type, failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BOARD_IS_BB(platform.board_id))
|
||||||
|
musb_am335x_deinit();
|
||||||
|
else
|
||||||
|
USB_MSG("Only AM335x driver available");
|
||||||
|
}
|
140
drivers/usbd/base/usbd.c
Executable file
140
drivers/usbd/base/usbd.c
Executable file
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* Entry point for USBD service, that handles USB HCDs
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ddekit/ddekit.h> /* ddekit_init */
|
||||||
|
#include <ddekit/thread.h> /* DDEKit threading */
|
||||||
|
|
||||||
|
#include <minix/devman.h> /* Initializing 'devman' */
|
||||||
|
#include <minix/sef.h> /* SEF handling */
|
||||||
|
|
||||||
|
#include <usb/usb_common.h>
|
||||||
|
#include <usb/usbd_interface.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Local declarations *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int usbd_sef_handler(int, sef_init_info_t *);
|
||||||
|
static int usbd_start(void);
|
||||||
|
static void usbd_init(void);
|
||||||
|
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 */
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* main *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
main(int UNUSED(argc), char * UNUSED(argv[]))
|
||||||
|
{
|
||||||
|
int ret_val;
|
||||||
|
|
||||||
|
USB_MSG("Starting USBD");
|
||||||
|
|
||||||
|
/* Basic SEF,DDE,... initialization */
|
||||||
|
usbd_init();
|
||||||
|
|
||||||
|
/* Assume failure unless usbd_start exits gracefully */
|
||||||
|
ret_val = EXIT_FAILURE;
|
||||||
|
|
||||||
|
/* USB host controllers initialization */
|
||||||
|
if (EXIT_SUCCESS == usbd_init_hcd()) {
|
||||||
|
|
||||||
|
/* Try initializing 'devman' */
|
||||||
|
if (EXIT_SUCCESS == devman_init()) {
|
||||||
|
|
||||||
|
/* Run USB driver (actually DDEKit threads)
|
||||||
|
* until this call returns: */
|
||||||
|
ret_val = usbd_start();
|
||||||
|
|
||||||
|
} else
|
||||||
|
USB_MSG("Initializing devman, failed");
|
||||||
|
|
||||||
|
/* Clean whatever was initialized */
|
||||||
|
usbd_deinit_hcd();
|
||||||
|
|
||||||
|
} else
|
||||||
|
USB_MSG("Initializing HCDs, failed");
|
||||||
|
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usbd_sef_handler *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
usbd_sef_handler(int type, sef_init_info_t * UNUSED(info))
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case SEF_INIT_FRESH:
|
||||||
|
USB_MSG("Initializing");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
case SEF_INIT_LU:
|
||||||
|
USB_MSG("Updating, not implemented");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
case SEF_INIT_RESTART:
|
||||||
|
USB_MSG("Restarting, not implemented");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
default:
|
||||||
|
USB_MSG("illegal SEF type");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usbd_start *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
usbd_start(void)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Driver's "main loop" is within DDEKit server thread */
|
||||||
|
if (NULL != ddekit_thread_create(usbd_server_thread, NULL, "USBD")) {
|
||||||
|
/* This will lock current thread until DDEKit terminates */
|
||||||
|
ddekit_minix_wait_exit();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
} else
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usbd_init *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
usbd_init(void)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Set one handler for all messages */
|
||||||
|
sef_setcb_init_fresh(usbd_sef_handler);
|
||||||
|
sef_setcb_init_lu(usbd_sef_handler);
|
||||||
|
sef_setcb_init_restart(usbd_sef_handler);
|
||||||
|
|
||||||
|
/* Initialize DDEkit (involves sef_startup()) */
|
||||||
|
ddekit_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usbd_server_thread *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
usbd_server_thread(void * UNUSED(unused))
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
ddekit_usb_server_init();
|
||||||
|
}
|
537
drivers/usbd/hcd/hcd.c
Executable file
537
drivers/usbd/hcd/hcd.c
Executable file
|
@ -0,0 +1,537 @@
|
||||||
|
/*
|
||||||
|
* Implementation of generic HCD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h> /* nanosleep */
|
||||||
|
#include <string.h> /* memcpy */
|
||||||
|
|
||||||
|
#include <usb/hcd_common.h>
|
||||||
|
#include <usb/hcd_ddekit.h>
|
||||||
|
#include <usb/hcd_interface.h>
|
||||||
|
#include <usb/usb_common.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Local declarations *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* Thread to handle device logic */
|
||||||
|
static void hcd_device_thread(void *);
|
||||||
|
|
||||||
|
/* Procedure that locks device thread forever in case of error/completion */
|
||||||
|
static void hcd_device_finish(hcd_device_state *, const char *);
|
||||||
|
|
||||||
|
/* Typical USD device communication procedures */
|
||||||
|
static int hcd_enumerate(hcd_device_state *);
|
||||||
|
static int hcd_get_device_descriptor(hcd_device_state *);
|
||||||
|
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 *);
|
||||||
|
|
||||||
|
/* For internal use by more general methods */
|
||||||
|
static int hcd_setup_packet(hcd_device_state *, hcd_ctrlrequest *);
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Local definitions *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* TODO: Only one device at a time */
|
||||||
|
static hcd_device_state hcd_device[1];
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_handle_event *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_handle_event(hcd_driver_state * driver)
|
||||||
|
{
|
||||||
|
hcd_device_state * this_device;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* TODO: Finding which hcd_device is in use should be performed here */
|
||||||
|
this_device = &(hcd_device[0]);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* 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) {
|
||||||
|
case HCD_EVENT_CONNECTED:
|
||||||
|
if (HCD_STATE_DISCONNECTED == this_device->state) {
|
||||||
|
if (EXIT_SUCCESS != hcd_connect_device(
|
||||||
|
this_device,
|
||||||
|
hcd_device_thread))
|
||||||
|
USB_MSG("Device creation failed");
|
||||||
|
} else
|
||||||
|
USB_MSG("Device not marked as 'disconnected' "
|
||||||
|
"for 'connection' event");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HCD_EVENT_DISCONNECTED:
|
||||||
|
if (HCD_STATE_DISCONNECTED != this_device->state) {
|
||||||
|
/* If connect callback was used before, call
|
||||||
|
* it's equivalent to signal disconnection */
|
||||||
|
if (HCD_STATE_CONNECTED == this_device->state)
|
||||||
|
hcd_disconnect_cb(this_device);
|
||||||
|
hcd_disconnect_device(this_device);
|
||||||
|
this_device->state = HCD_STATE_DISCONNECTED;
|
||||||
|
} else
|
||||||
|
USB_MSG("Device is marked as 'disconnected' "
|
||||||
|
"for 'disconnection' event");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HCD_EVENT_ENDPOINT:
|
||||||
|
/* Allow device thread to continue with it's logic */
|
||||||
|
if (HCD_STATE_DISCONNECTED != this_device->state)
|
||||||
|
hcd_device_continue(this_device);
|
||||||
|
else
|
||||||
|
USB_MSG("Device is marked as 'disconnected' "
|
||||||
|
"for 'EP' event");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
USB_ASSERT(0, "Illegal HCD event");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_device_thread *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_device_thread(void * thread_args)
|
||||||
|
{
|
||||||
|
hcd_device_state * this_device;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Retrieve structures from generic data */
|
||||||
|
this_device = (hcd_device_state *)thread_args;
|
||||||
|
|
||||||
|
/* Plugged in */
|
||||||
|
this_device->state = HCD_STATE_CONNECTION_PENDING;
|
||||||
|
|
||||||
|
/* Enumeration sequence */
|
||||||
|
if (EXIT_SUCCESS != hcd_enumerate(this_device))
|
||||||
|
hcd_device_finish(this_device, "USB device enumeration failed");
|
||||||
|
|
||||||
|
/* Tell everyone that device was connected */
|
||||||
|
hcd_connect_cb(this_device);
|
||||||
|
|
||||||
|
/* Fully configured */
|
||||||
|
this_device->state = HCD_STATE_CONNECTED;
|
||||||
|
|
||||||
|
USB_DBG("Waiting for URBs");
|
||||||
|
|
||||||
|
/* No URB's yet */
|
||||||
|
this_device->urb = NULL;
|
||||||
|
|
||||||
|
/* Start handling URB's */
|
||||||
|
for(;;) {
|
||||||
|
/* Block and wait for something like 'submit URB' */
|
||||||
|
hcd_device_wait(this_device);
|
||||||
|
|
||||||
|
if (EXIT_SUCCESS != hcd_handle_urb(this_device))
|
||||||
|
hcd_device_finish(this_device, "URB handling failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finish device handling to avoid leaving thread */
|
||||||
|
hcd_device_finish(this_device, "USB device handling completed");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_device_finish *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_device_finish(hcd_device_state * this_device, const char * finish_msg)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
USB_MSG("USB device handling finished with message: '%s'", finish_msg);
|
||||||
|
|
||||||
|
/* Lock forever */
|
||||||
|
for (;;) {
|
||||||
|
hcd_device_wait(this_device);
|
||||||
|
USB_MSG("Failed attempt to continue finished thread");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_enumerate *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_enumerate(hcd_device_state * this_device)
|
||||||
|
{
|
||||||
|
hcd_driver_state * d;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Get device descriptor */
|
||||||
|
if (EXIT_SUCCESS != hcd_get_device_descriptor(this_device)) {
|
||||||
|
USB_MSG("Failed to get device descriptor");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: dynamic device address when more devices are available */
|
||||||
|
|
||||||
|
/* Set address */
|
||||||
|
if (EXIT_SUCCESS != hcd_set_address(this_device, HCD_ATTACHED_ADDR)) {
|
||||||
|
USB_MSG("Failed to set device address");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set parameters for further communication */
|
||||||
|
d->setup_device(d->private_data, HCD_DEFAULT_EP, HCD_ATTACHED_ADDR);
|
||||||
|
|
||||||
|
/* Get other descriptors */
|
||||||
|
if (EXIT_SUCCESS != hcd_get_descriptor_tree(this_device)) {
|
||||||
|
USB_MSG("Failed to get configuration descriptor tree");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: always first configuration */
|
||||||
|
/* Set configuration */
|
||||||
|
if (EXIT_SUCCESS != hcd_set_configuration(this_device, 0x01)) {
|
||||||
|
USB_MSG("Failed to set configuration");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_DBG("Enumeration completed");
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_get_device_descriptor *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_get_device_descriptor(hcd_device_state * this_device)
|
||||||
|
{
|
||||||
|
hcd_ctrlrequest setup;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* TODO: magic numbers, no header for these */
|
||||||
|
|
||||||
|
/* Format setup packet */
|
||||||
|
setup.bRequestType = 0x80; /* IN */
|
||||||
|
setup.bRequest = 0x06; /* Get descriptor */
|
||||||
|
setup.wValue = 0x0100; /* Device */
|
||||||
|
setup.wIndex = 0x0000;
|
||||||
|
setup.wLength = sizeof(this_device->device_desc);
|
||||||
|
|
||||||
|
/* Handle formatted setup packet */
|
||||||
|
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup)) {
|
||||||
|
USB_MSG("Handling setup packet failed");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put what was read in device descriptor */
|
||||||
|
memcpy(&(this_device->device_desc), this_device->buffer,
|
||||||
|
sizeof(this_device->device_desc));
|
||||||
|
|
||||||
|
/* 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]);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_set_address *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_set_address(hcd_device_state * this_device, int address)
|
||||||
|
{
|
||||||
|
hcd_ctrlrequest setup;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
USB_ASSERT((address > 0) && (address < 128), "Illegal address");
|
||||||
|
|
||||||
|
/* TODO: magic numbers, no header for these */
|
||||||
|
setup.bRequestType = 0x00; /* OUT */
|
||||||
|
setup.bRequest = 0x05; /* Set address */
|
||||||
|
setup.wValue = address;
|
||||||
|
setup.wIndex = 0x0000;
|
||||||
|
setup.wLength = 0x0000;
|
||||||
|
|
||||||
|
/* Handle formatted setup packet */
|
||||||
|
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup)) {
|
||||||
|
USB_MSG("Handling setup packet failed");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Sleep 5ms for proper addressing */
|
||||||
|
struct timespec nanotm = {0, HCD_NANOSLEEP_MSEC(5)};
|
||||||
|
nanosleep(&nanotm, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_get_descriptor_tree *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_get_descriptor_tree(hcd_device_state * this_device)
|
||||||
|
{
|
||||||
|
hcd_config_descriptor config_descriptor;
|
||||||
|
hcd_ctrlrequest setup;
|
||||||
|
int completed;
|
||||||
|
int total_length;
|
||||||
|
int buffer_length;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* First, ask only for configuration itself to get length info */
|
||||||
|
buffer_length = sizeof(config_descriptor);
|
||||||
|
completed = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* TODO: configuration 0 is hard-coded
|
||||||
|
* but others are rarely used anyway */
|
||||||
|
/* TODO: magic numbers, no header for these */
|
||||||
|
setup.bRequestType = 0x80; /* IN */
|
||||||
|
setup.bRequest = 0x06; /* Get descriptor */
|
||||||
|
setup.wValue = 0x0200; /* Configuration 0 */
|
||||||
|
setup.wIndex = 0x0000;
|
||||||
|
setup.wLength = buffer_length;
|
||||||
|
|
||||||
|
/* Handle formatted setup packet */
|
||||||
|
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup)) {
|
||||||
|
USB_MSG("Handling setup packet failed");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we only asked for configuration itself
|
||||||
|
* then ask again for other descriptors */
|
||||||
|
if (sizeof(config_descriptor) == buffer_length) {
|
||||||
|
|
||||||
|
/* Put what was read in configuration descriptor */
|
||||||
|
memcpy(&config_descriptor, this_device->buffer,
|
||||||
|
sizeof(config_descriptor));
|
||||||
|
|
||||||
|
/* Continue only if there is more data */
|
||||||
|
total_length = config_descriptor.wTotalLength[0] +
|
||||||
|
(config_descriptor.wTotalLength[1] << 8);
|
||||||
|
|
||||||
|
if (total_length < (int)sizeof(config_descriptor)) {
|
||||||
|
/* This should never happen for a fine device */
|
||||||
|
USB_MSG("Illegal wTotalLength value");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
else if (sizeof(config_descriptor) == total_length) {
|
||||||
|
/* Nothing more was in descriptor anyway */
|
||||||
|
completed = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Read whatever is needed */
|
||||||
|
buffer_length = total_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* All data for given configuration was read */
|
||||||
|
completed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!completed);
|
||||||
|
|
||||||
|
/* Create tree based on received buffer */
|
||||||
|
if (EXIT_SUCCESS != hcd_buffer_to_tree(this_device->buffer,
|
||||||
|
this_device->data_len,
|
||||||
|
&(this_device->config_tree))) {
|
||||||
|
/* This should never happen for a fine device */
|
||||||
|
USB_MSG("Illegal descriptor values");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_set_configuration *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_set_configuration(hcd_device_state * this_device, int configuration)
|
||||||
|
{
|
||||||
|
hcd_ctrlrequest setup;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* TODO: magic numbers, no header for these */
|
||||||
|
setup.bRequestType = 0x00; /* OUT */
|
||||||
|
setup.bRequest = 0x09; /* Set configuration */
|
||||||
|
setup.wValue = configuration;
|
||||||
|
setup.wIndex = 0x0000;
|
||||||
|
setup.wLength = 0x0000;
|
||||||
|
|
||||||
|
/* Handle formatted setup packet */
|
||||||
|
if (EXIT_SUCCESS != hcd_setup_packet(this_device, &setup)) {
|
||||||
|
USB_MSG("Handling setup packet failed");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_handle_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_handle_urb(hcd_device_state * this_device)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
USB_ASSERT(NULL != this_device->urb, "NULL URB received");
|
||||||
|
|
||||||
|
/* TODO: URB handling will be here */
|
||||||
|
|
||||||
|
/* TODO: call completion */
|
||||||
|
/* hcd_completion_cb */
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_setup_packet *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_setup_packet(hcd_device_state * this_device, hcd_ctrlrequest * setup)
|
||||||
|
{
|
||||||
|
hcd_driver_state * d;
|
||||||
|
hcd_reg1 * current_byte;
|
||||||
|
int expected_len;
|
||||||
|
int received_len;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Initially... */
|
||||||
|
d = this_device->driver;
|
||||||
|
expected_len = (int)setup->wLength;
|
||||||
|
current_byte = this_device->buffer;
|
||||||
|
|
||||||
|
/* Send setup packet */
|
||||||
|
d->setup_stage(d->private_data, setup);
|
||||||
|
|
||||||
|
/* Wait for response */
|
||||||
|
hcd_device_wait(this_device);
|
||||||
|
|
||||||
|
/* Check response */
|
||||||
|
if (EXIT_SUCCESS != d->check_error(d->private_data))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
/* For data packets... */
|
||||||
|
if (expected_len > 0) {
|
||||||
|
|
||||||
|
/* TODO: magic number */
|
||||||
|
/* ...IN data packets */
|
||||||
|
if (setup->bRequestType & 0x80) {
|
||||||
|
|
||||||
|
/* What was received until now */
|
||||||
|
this_device->data_len = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* Try getting data */
|
||||||
|
d->in_data_stage(d->private_data);
|
||||||
|
|
||||||
|
/* Wait for response */
|
||||||
|
hcd_device_wait(this_device);
|
||||||
|
|
||||||
|
/* Check response */
|
||||||
|
if (EXIT_SUCCESS != d->check_error(
|
||||||
|
d->private_data))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
/* Read data received as response */
|
||||||
|
received_len = d->read_data(d->private_data,
|
||||||
|
current_byte, 0);
|
||||||
|
|
||||||
|
/* Data reading should always yield positive
|
||||||
|
* results for proper setup packet */
|
||||||
|
if (received_len > 0) {
|
||||||
|
/* Try next packet */
|
||||||
|
this_device->data_len += received_len;
|
||||||
|
current_byte += received_len;
|
||||||
|
} else
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
} while (expected_len > this_device->data_len);
|
||||||
|
|
||||||
|
/* Should be exactly what we requested, no more */
|
||||||
|
if (this_device->data_len != expected_len) {
|
||||||
|
USB_MSG("Received more data than expected");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* TODO: unimplemented */
|
||||||
|
USB_MSG("Illegal non-zero length OUT setup packet");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status stages */
|
||||||
|
if (setup->bRequestType & 0x80) {
|
||||||
|
|
||||||
|
/* Try confirming data receive */
|
||||||
|
d->out_status_stage(d->private_data);
|
||||||
|
|
||||||
|
/* Wait for response */
|
||||||
|
hcd_device_wait(this_device);
|
||||||
|
|
||||||
|
/* Check response */
|
||||||
|
if (EXIT_SUCCESS != d->check_error(d->private_data))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Try getting status confirmation */
|
||||||
|
d->in_status_stage(d->private_data);
|
||||||
|
|
||||||
|
/* Wait for response */
|
||||||
|
hcd_device_wait(this_device);
|
||||||
|
|
||||||
|
/* Check response */
|
||||||
|
if (EXIT_SUCCESS != d->check_error(d->private_data))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
/* Read zero data from response to clear registers */
|
||||||
|
if (0 != d->read_data(d->private_data, NULL, 0))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
490
drivers/usbd/hcd/hcd_common.c
Executable file
490
drivers/usbd/hcd/hcd_common.c
Executable file
|
@ -0,0 +1,490 @@
|
||||||
|
/*
|
||||||
|
* Implementation of commonly used procedures for HCD handling/initialization
|
||||||
|
* If possible, everything OS specific should be here
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h> /* memset... */
|
||||||
|
|
||||||
|
#include <sys/mman.h> /* Physical to virtual memory mapping */
|
||||||
|
|
||||||
|
#include <ddekit/interrupt.h> /* DDEKit based interrupt handling */
|
||||||
|
|
||||||
|
#include <minix/clkconf.h> /* clkconf_* */
|
||||||
|
#include <minix/syslib.h> /* sys_privctl */
|
||||||
|
|
||||||
|
#include <usb/hcd_common.h>
|
||||||
|
#include <usb/usb_common.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Local prototypes *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int hcd_fill_configuration(hcd_reg1 *, int, hcd_configuration *, int);
|
||||||
|
static int hcd_fill_interface(hcd_reg1 *, int, hcd_interface *, int);
|
||||||
|
static int hcd_fill_endpoint(hcd_reg1 *, int, hcd_endpoint *, int);
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_os_interrupt_attach *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
hcd_os_interrupt_attach(int irq, void (*init)(void *),
|
||||||
|
void (*isr)(void *), void *priv)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
if (NULL == ddekit_interrupt_attach(irq, 0, init, isr, priv)) {
|
||||||
|
USB_MSG("Attaching interrupt %d failed", irq);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_os_interrupt_detach *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_os_interrupt_detach(int irq)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
ddekit_interrupt_detach(irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_os_interrupt_enable *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_os_interrupt_enable(int irq)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
ddekit_interrupt_enable(irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_os_interrupt_disable *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_os_interrupt_disable(int irq)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
ddekit_interrupt_disable(irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_os_regs_init *
|
||||||
|
*===========================================================================*/
|
||||||
|
void *
|
||||||
|
hcd_os_regs_init(unsigned long base_addr, unsigned long addr_len)
|
||||||
|
{
|
||||||
|
/* Memory range where we need privileged access */
|
||||||
|
struct minix_mem_range mr;
|
||||||
|
|
||||||
|
/* NULL unless initialization was fully completed */
|
||||||
|
void * virt_reg_base;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
virt_reg_base = NULL;
|
||||||
|
|
||||||
|
/* Must have been set before */
|
||||||
|
USB_ASSERT(0 != base_addr, "Invalid base address!");
|
||||||
|
USB_ASSERT(0 != addr_len, "Invalid base length!");
|
||||||
|
|
||||||
|
/* Set memory range for peripheral */
|
||||||
|
mr.mr_base = base_addr;
|
||||||
|
mr.mr_limit = base_addr + addr_len;
|
||||||
|
|
||||||
|
/* Try getting access to memory range */
|
||||||
|
if (EXIT_SUCCESS == sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr)) {
|
||||||
|
|
||||||
|
/* And map it where we want it */
|
||||||
|
virt_reg_base = vm_map_phys(SELF, (void *)base_addr, addr_len);
|
||||||
|
|
||||||
|
/* Check for mapping errors to allow us returning NULL */
|
||||||
|
if (MAP_FAILED == virt_reg_base) {
|
||||||
|
USB_MSG("Mapping memory with vm_map_phys() failed");
|
||||||
|
virt_reg_base = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else
|
||||||
|
USB_MSG("Acquiring memory with sys_privctl() failed");
|
||||||
|
|
||||||
|
return virt_reg_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_os_regs_deinit *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
hcd_os_regs_deinit(unsigned long base_addr, unsigned long addr_len)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* To keep USBD return value convention */
|
||||||
|
return (0 == vm_unmap_phys(SELF, (void*)base_addr, addr_len)) ?
|
||||||
|
EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_os_clkconf *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
hcd_os_clkconf(unsigned long clk, unsigned long mask, unsigned long value)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Apparently clkconf_init may be called more than once anyway */
|
||||||
|
if ((0 == clkconf_init()) && (0 == clkconf_set(clk, mask, value)))
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
else
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_os_clkconf_release *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
hcd_os_clkconf_release(void)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
return clkconf_release();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_init_device *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
hcd_connect_device(hcd_device_state * this_device, hcd_thread_function funct)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
if ((NULL != this_device->lock) || (NULL != this_device->thread)) {
|
||||||
|
USB_MSG("Device data already allocated");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL == (this_device->lock = ddekit_sem_init(0)))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (NULL == (this_device->thread = ddekit_thread_create(funct,
|
||||||
|
this_device,
|
||||||
|
"Device"))) {
|
||||||
|
ddekit_sem_deinit(this_device->lock);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allow device thread to work */
|
||||||
|
ddekit_yield();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_deinit_device *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_disconnect_device(hcd_device_state * this_device)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
hcd_tree_cleanup(&(this_device->config_tree));
|
||||||
|
|
||||||
|
/* TODO: spilled resources */
|
||||||
|
ddekit_thread_terminate(this_device->thread);
|
||||||
|
ddekit_sem_deinit(this_device->lock);
|
||||||
|
|
||||||
|
this_device->thread = NULL;
|
||||||
|
this_device->lock = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_device_wait *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_device_wait(hcd_device_state * this_device)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
ddekit_sem_down(this_device->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_device_continue *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_device_continue(hcd_device_state * this_device)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
ddekit_sem_up(this_device->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_buffer_to_tree *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
hcd_buffer_to_tree(hcd_reg1 * buf, int len, hcd_configuration * c)
|
||||||
|
{
|
||||||
|
hcd_interface * i;
|
||||||
|
hcd_endpoint * e;
|
||||||
|
hcd_descriptor * desc;
|
||||||
|
int cfg_num;
|
||||||
|
int if_num;
|
||||||
|
int ep_num;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
cfg_num = 0;
|
||||||
|
if_num = 0;
|
||||||
|
ep_num = 0;
|
||||||
|
|
||||||
|
i = NULL;
|
||||||
|
e = NULL;
|
||||||
|
|
||||||
|
/* Cleanup initially to NULL pointers before any allocation */
|
||||||
|
memset(c, 0, sizeof(*c));
|
||||||
|
|
||||||
|
while (len > (int)sizeof(*desc)) {
|
||||||
|
/* Check descriptor type */
|
||||||
|
desc = (hcd_descriptor *)buf;
|
||||||
|
|
||||||
|
if (UDESC_CONFIG == desc->bDescriptorType) {
|
||||||
|
if (EXIT_SUCCESS != hcd_fill_configuration(buf, len,
|
||||||
|
c, cfg_num++))
|
||||||
|
goto PARSE_ERROR;
|
||||||
|
|
||||||
|
if_num = 0;
|
||||||
|
}
|
||||||
|
else if (UDESC_INTERFACE == desc->bDescriptorType) {
|
||||||
|
if (NULL == c->interface)
|
||||||
|
goto PARSE_ERROR;
|
||||||
|
|
||||||
|
i = &(c->interface[if_num]);
|
||||||
|
|
||||||
|
if (EXIT_SUCCESS != hcd_fill_interface(buf, len,
|
||||||
|
i, if_num++))
|
||||||
|
goto PARSE_ERROR;
|
||||||
|
|
||||||
|
ep_num = 0;
|
||||||
|
}
|
||||||
|
else if (UDESC_ENDPOINT == desc->bDescriptorType) {
|
||||||
|
if (NULL == c->interface)
|
||||||
|
goto PARSE_ERROR;
|
||||||
|
|
||||||
|
if (NULL == i)
|
||||||
|
goto PARSE_ERROR;
|
||||||
|
|
||||||
|
e = &(i->endpoint[ep_num]);
|
||||||
|
|
||||||
|
if (EXIT_SUCCESS != hcd_fill_endpoint(buf, len,
|
||||||
|
e, ep_num++))
|
||||||
|
goto PARSE_ERROR;
|
||||||
|
} else
|
||||||
|
USB_DBG("Unhandled descriptor type 0x%02X",
|
||||||
|
desc->bDescriptorType);
|
||||||
|
|
||||||
|
len -= desc->bLength;
|
||||||
|
buf += desc->bLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != len) {
|
||||||
|
USB_MSG("After parsing, some descriptor data remains");
|
||||||
|
goto PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
PARSE_ERROR:
|
||||||
|
hcd_tree_cleanup(c);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_tree_cleanup *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_tree_cleanup(hcd_configuration * c)
|
||||||
|
{
|
||||||
|
int if_idx;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Free if anything was allocated */
|
||||||
|
if (NULL != c->interface) {
|
||||||
|
|
||||||
|
USB_ASSERT(c->num_interfaces > 0, "Interface number error");
|
||||||
|
|
||||||
|
for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) {
|
||||||
|
if (NULL != c->interface[if_idx].endpoint) {
|
||||||
|
USB_DBG("Freeing ep for interface #%d", if_idx);
|
||||||
|
free(c->interface[if_idx].endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_DBG("Freeing interfaces");
|
||||||
|
free(c->interface);
|
||||||
|
c->interface = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_fill_configuration *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_fill_configuration(hcd_reg1 * buf, int len, hcd_configuration * c, int num)
|
||||||
|
{
|
||||||
|
hcd_config_descriptor * desc;
|
||||||
|
int interfaces_size;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
desc = (hcd_config_descriptor *)buf;
|
||||||
|
|
||||||
|
USB_DBG("Configuration #%d", num);
|
||||||
|
|
||||||
|
if (num > 0) {
|
||||||
|
USB_DBG("Only one configuration possible");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UDESC_CONFIG != desc->bDescriptorType)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (desc->bLength > len)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (sizeof(*desc) != desc->bLength)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
memcpy(&(c->descriptor), buf, sizeof(c->descriptor));
|
||||||
|
|
||||||
|
c->num_interfaces = c->descriptor.bNumInterface;
|
||||||
|
|
||||||
|
interfaces_size = c->num_interfaces * sizeof(*(c->interface));
|
||||||
|
|
||||||
|
USB_DBG("Allocating interfaces, %dB", interfaces_size);
|
||||||
|
c->interface = malloc(interfaces_size);
|
||||||
|
|
||||||
|
memset(c->interface, 0, interfaces_size);
|
||||||
|
|
||||||
|
/* Dump configuration in debug mode */
|
||||||
|
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("bNumInterface %02X", desc->bNumInterface);
|
||||||
|
USB_DBG("bConfigurationValue %02X", desc->bConfigurationValue);
|
||||||
|
USB_DBG("iConfiguration %02X", desc->iConfiguration);
|
||||||
|
USB_DBG("bmAttributes %02X", desc->bmAttributes);
|
||||||
|
USB_DBG("bMaxPower %02X", desc->bMaxPower);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_fill_interface *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_fill_interface(hcd_reg1 * buf, int len, hcd_interface * i, int num)
|
||||||
|
{
|
||||||
|
hcd_interface_descriptor * desc;
|
||||||
|
int endpoints_size;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
desc = (hcd_interface_descriptor *)buf;
|
||||||
|
|
||||||
|
USB_DBG("Interface #%d", num);
|
||||||
|
|
||||||
|
if (UDESC_INTERFACE != desc->bDescriptorType)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (desc->bLength > len)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (sizeof(*desc) != desc->bLength)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (desc->bInterfaceNumber != num)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
memcpy(&(i->descriptor), buf, sizeof(i->descriptor));
|
||||||
|
|
||||||
|
i->num_endpoints = i->descriptor.bNumEndpoints;
|
||||||
|
|
||||||
|
endpoints_size = i->num_endpoints * sizeof(*(i->endpoint));
|
||||||
|
|
||||||
|
USB_DBG("Allocating endpoints, %dB", endpoints_size);
|
||||||
|
i->endpoint = malloc(endpoints_size);
|
||||||
|
|
||||||
|
memset(i->endpoint, 0, endpoints_size);
|
||||||
|
|
||||||
|
/* Dump interface in debug mode */
|
||||||
|
USB_DBG("<<INTERFACE>>");
|
||||||
|
USB_DBG("bLength %02X", desc->bLength);
|
||||||
|
USB_DBG("bDescriptorType %02X", desc->bDescriptorType);
|
||||||
|
USB_DBG("bInterfaceNumber %02X", desc->bInterfaceNumber);
|
||||||
|
USB_DBG("bAlternateSetting %02X", desc->bAlternateSetting);
|
||||||
|
USB_DBG("bNumEndpoints %02X", desc->bNumEndpoints);
|
||||||
|
USB_DBG("bInterfaceClass %02X", desc->bInterfaceClass);
|
||||||
|
USB_DBG("bInterfaceSubClass %02X", desc->bInterfaceSubClass);
|
||||||
|
USB_DBG("bInterfaceProtocol %02X", desc->bInterfaceProtocol);
|
||||||
|
USB_DBG("iInterface %02X", desc->iInterface);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_fill_endpoint *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_fill_endpoint(hcd_reg1 * buf, int len, hcd_endpoint * e, int num)
|
||||||
|
{
|
||||||
|
hcd_endpoint_descriptor * desc;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
desc = (hcd_endpoint_descriptor *)buf;
|
||||||
|
|
||||||
|
USB_DBG("Endpoint #%d", num);
|
||||||
|
|
||||||
|
if (UDESC_ENDPOINT != desc->bDescriptorType)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (desc->bLength > len)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (sizeof(*desc) != desc->bLength)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
memcpy(&(e->descriptor), buf, sizeof(e->descriptor));
|
||||||
|
|
||||||
|
/* Dump endpoint in debug mode */
|
||||||
|
USB_DBG("<<ENDPOINT>>");
|
||||||
|
USB_DBG("bLength %02X", desc->bLength);
|
||||||
|
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("bInterval %02X", desc->bInterval);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
277
drivers/usbd/hcd/hcd_ddekit.c
Executable file
277
drivers/usbd/hcd/hcd_ddekit.c
Executable file
|
@ -0,0 +1,277 @@
|
||||||
|
/*
|
||||||
|
* Implementation of DDEkit related calls/data
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h> /* memset */
|
||||||
|
|
||||||
|
#include <ddekit/usb.h>
|
||||||
|
|
||||||
|
#include <usb/hcd_ddekit.h>
|
||||||
|
#include <usb/usb_common.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Local declarations *
|
||||||
|
*===========================================================================*/
|
||||||
|
/*
|
||||||
|
* In this file "struct ddekit_usb_dev" equals "hcd_device_state"
|
||||||
|
* */
|
||||||
|
struct ddekit_usb_device_id;
|
||||||
|
struct ddekit_usb_urb;
|
||||||
|
struct ddekit_usb_dev;
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Global definitions *
|
||||||
|
*===========================================================================*/
|
||||||
|
ddekit_usb_completion_cb completion_cb = NULL;
|
||||||
|
ddekit_usb_connect_cb connect_cb = NULL;
|
||||||
|
ddekit_usb_disconnect_cb disconnect_cb = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Implementation for usb_server.c *
|
||||||
|
*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* _ddekit_usb_get_manufacturer *
|
||||||
|
*===========================================================================*/
|
||||||
|
char *
|
||||||
|
_ddekit_usb_get_manufacturer(struct ddekit_usb_dev * ddev)
|
||||||
|
{
|
||||||
|
static const char mfg[] = "UNKNOWN";
|
||||||
|
DEBUG_DUMP;
|
||||||
|
/* TODO: UNUSED won't work */
|
||||||
|
((void)ddev);
|
||||||
|
return (char *)mfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* _ddekit_usb_get_product *
|
||||||
|
*===========================================================================*/
|
||||||
|
char *
|
||||||
|
_ddekit_usb_get_product(struct ddekit_usb_dev * ddev)
|
||||||
|
{
|
||||||
|
static const char prod[] = "UNKNOWN";
|
||||||
|
DEBUG_DUMP;
|
||||||
|
/* TODO: UNUSED won't work */
|
||||||
|
((void)ddev);
|
||||||
|
return (char *)prod;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* _ddekit_usb_get_serial *
|
||||||
|
*===========================================================================*/
|
||||||
|
char *
|
||||||
|
_ddekit_usb_get_serial(struct ddekit_usb_dev * ddev)
|
||||||
|
{
|
||||||
|
static const char serial[] = "UNKNOWN";
|
||||||
|
DEBUG_DUMP;
|
||||||
|
/* TODO: UNUSED won't work */
|
||||||
|
((void)ddev);
|
||||||
|
return (char *)serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* _ddekit_usb_get_device_desc *
|
||||||
|
*===========================================================================*/
|
||||||
|
struct usb_device_descriptor *
|
||||||
|
_ddekit_usb_get_device_desc(struct ddekit_usb_dev * ddev)
|
||||||
|
{
|
||||||
|
hcd_device_state * dev;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
dev = (hcd_device_state *)ddev;
|
||||||
|
|
||||||
|
return (struct usb_device_descriptor *)
|
||||||
|
(&(dev->config_tree.descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* _ddekit_usb_get_interface_desc *
|
||||||
|
*===========================================================================*/
|
||||||
|
struct usb_interface_descriptor *
|
||||||
|
_ddekit_usb_get_interface_desc(struct ddekit_usb_dev * ddev, int inum)
|
||||||
|
{
|
||||||
|
hcd_device_state * dev;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
dev = (hcd_device_state *)ddev;
|
||||||
|
|
||||||
|
return (struct usb_interface_descriptor *)
|
||||||
|
(&(dev->config_tree.interface[inum].descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Implementation for <ddekit/usb.h> *
|
||||||
|
*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* ddekit_usb_dev_set_data *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
ddekit_usb_dev_set_data(struct ddekit_usb_dev * dev, void * data)
|
||||||
|
{
|
||||||
|
hcd_device_state * hcd_dev;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
hcd_dev = (hcd_device_state *)dev;
|
||||||
|
|
||||||
|
hcd_dev->data = data;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* ddekit_usb_dev_get_data *
|
||||||
|
*===========================================================================*/
|
||||||
|
void *
|
||||||
|
ddekit_usb_dev_get_data(struct ddekit_usb_dev * dev)
|
||||||
|
{
|
||||||
|
hcd_device_state * hcd_dev;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
hcd_dev = (hcd_device_state *)dev;
|
||||||
|
|
||||||
|
return hcd_dev->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: This was in header file but is not used anywhere */
|
||||||
|
#if 0
|
||||||
|
/*===========================================================================*
|
||||||
|
* ddekit_usb_get_device_id *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
ddekit_usb_get_device_id(struct ddekit_usb_dev * dev,
|
||||||
|
struct ddekit_usb_device_id * id)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
/* TODO: UNUSED won't work */
|
||||||
|
((void)dev);
|
||||||
|
((void)id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* ddekit_usb_submit_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
ddekit_usb_submit_urb(struct ddekit_usb_urb * d_urb)
|
||||||
|
{
|
||||||
|
hcd_urb * urb;
|
||||||
|
hcd_device_state * dev;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
urb = (hcd_urb *)d_urb;
|
||||||
|
dev = (hcd_device_state *)(urb->dev);
|
||||||
|
|
||||||
|
/* TODO: queue URB's */
|
||||||
|
/* Reassign and go to thread */
|
||||||
|
dev->urb = urb;
|
||||||
|
hcd_device_continue(dev);
|
||||||
|
dev->urb = NULL;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* ddekit_usb_cancle_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
ddekit_usb_cancle_urb(struct ddekit_usb_urb * d_urb)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
/* TODO: UNUSED won't work */
|
||||||
|
((void)d_urb);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* ddekit_usb_init *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
ddekit_usb_init(struct ddekit_usb_driver * drv,
|
||||||
|
ddekit_usb_malloc_fn * _m,
|
||||||
|
ddekit_usb_free_fn * _f)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
completion_cb = drv->completion;
|
||||||
|
connect_cb = drv->connect;
|
||||||
|
disconnect_cb = drv->disconnect;
|
||||||
|
|
||||||
|
*_m = malloc;
|
||||||
|
*_f = free;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_connect_cb *
|
||||||
|
*===========================================================================*/
|
||||||
|
void hcd_connect_cb(hcd_device_state * dev)
|
||||||
|
{
|
||||||
|
unsigned int if_bitmask;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* TODO: magic numbers like in ddekit/devman */
|
||||||
|
/* Each bit starting from 0, represents valid interface */
|
||||||
|
if_bitmask = 0xFFFFFFFF >> (32 - dev->config_tree.num_interfaces);
|
||||||
|
|
||||||
|
USB_DBG("Interfaces %d, mask %08X",
|
||||||
|
dev->config_tree.num_interfaces,
|
||||||
|
if_bitmask);
|
||||||
|
|
||||||
|
connect_cb((struct ddekit_usb_dev *)dev, (int)if_bitmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_disconnect_cb *
|
||||||
|
*===========================================================================*/
|
||||||
|
void hcd_disconnect_cb(hcd_device_state * dev)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
disconnect_cb((struct ddekit_usb_dev *)dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_completion_cb *
|
||||||
|
*===========================================================================*/
|
||||||
|
void hcd_completion_cb(void * priv)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
completion_cb(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: to be removed when this is linkable */
|
||||||
|
/*===========================================================================*
|
||||||
|
* get_bp *
|
||||||
|
*===========================================================================*/
|
||||||
|
unsigned int get_bp(void)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
718
drivers/usbd/hcd/musb/musb_am335x.c
Executable file
718
drivers/usbd/hcd/musb/musb_am335x.c
Executable file
|
@ -0,0 +1,718 @@
|
||||||
|
/*
|
||||||
|
* Implementation of whatever is hardware specific in AM335x MCU
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h> /* memset */
|
||||||
|
#include <time.h> /* nanosleep */
|
||||||
|
|
||||||
|
#include <usb/hcd_common.h>
|
||||||
|
#include <usb/hcd_platforms.h>
|
||||||
|
#include <usb/hcd_interface.h>
|
||||||
|
#include <usb/usb_common.h>
|
||||||
|
|
||||||
|
#include "musb_core.h"
|
||||||
|
|
||||||
|
/* TODO: BeagleBone white uses USB0 for PC connection as peripheral */
|
||||||
|
#undef AM335X_USE_USB0
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* 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_IRQSTATRAW 0x024u
|
||||||
|
#define AM335X_REG_IRQSTAT 0x028u
|
||||||
|
#define AM335X_REG_IRQENABLER 0x02Cu
|
||||||
|
#define AM335X_REG_IRQCLEARR 0x030u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDTX00 0x100u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDTX01 0x104u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDTX02 0x108u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDTX03 0x10Cu
|
||||||
|
#define AM335X_REG_IRQDMATHOLDRX00 0x110u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDRX01 0x114u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDRX02 0x118u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDRX03 0x11Cu
|
||||||
|
#define AM335X_REG_IRQDMATHOLDTX10 0x120u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDTX11 0x124u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDTX12 0x128u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDTX13 0x12Cu
|
||||||
|
#define AM335X_REG_IRQDMATHOLDRX10 0x130u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDRX11 0x134u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDRX12 0x138u
|
||||||
|
#define AM335X_REG_IRQDMATHOLDRX13 0x13Cu
|
||||||
|
#define AM335X_REG_IRQDMAENABLE0 0x140u
|
||||||
|
#define AM335X_REG_IRQDMAENABLE1 0x144u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDTX00 0x200u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDTX01 0x204u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDTX02 0x208u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDTX03 0x20Cu
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDRX00 0x210u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDRX01 0x214u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDRX02 0x218u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDRX03 0x21Cu
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDTX10 0x220u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDTX11 0x224u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDTX12 0x228u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDTX13 0x22Cu
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDRX10 0x230u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDRX11 0x234u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDRX12 0x238u
|
||||||
|
#define AM335X_REG_IRQFRAMETHOLDRX13 0x23Cu
|
||||||
|
#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_REG_USBXIRQMSTAT 0x20u
|
||||||
|
#define AM335X_REG_USBXIRQSTATRAW0 0x28u
|
||||||
|
#define AM335X_REG_USBXIRQSTATRAW1 0x2Cu
|
||||||
|
#define AM335X_REG_USBXIRQSTAT0 0x30u
|
||||||
|
#define AM335X_REG_USBXIRQSTAT1 0x34u
|
||||||
|
#define AM335X_REG_USBXIRQENABLESET0 0x38u
|
||||||
|
#define AM335X_REG_USBXIRQENABLESET1 0x3Cu
|
||||||
|
#define AM335X_REG_USBXIRQENABLECLR0 0x40u
|
||||||
|
#define AM335X_REG_USBXIRQENABLECLR1 0x44u
|
||||||
|
#define AM335X_REG_USBXTXMODE 0x70u
|
||||||
|
#define AM335X_REG_USBXRXMODE 0x74u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP1 0x80u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP2 0x84u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP3 0x88u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP4 0x8Cu
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP5 0x90u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP6 0x94u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP7 0x98u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP8 0x9Cu
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP9 0xA0u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP10 0xA4u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP11 0xA8u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP12 0xACu
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP13 0xB0u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP14 0xB4u
|
||||||
|
#define AM335X_REG_USBXGENRNDISEP15 0xB8u
|
||||||
|
#define AM335X_REG_USBXAUTOREQ 0xD0u
|
||||||
|
#define AM335X_REG_USBXSRPFIXTIME 0xD4u
|
||||||
|
#define AM335X_REG_USBX_TDOWN 0xD8u
|
||||||
|
#define AM335X_REG_USBXUTMI 0xE0u
|
||||||
|
#define AM335X_REG_USBXMGCUTMILB 0xE4u
|
||||||
|
#define AM335X_REG_USBXMODE 0xE8u
|
||||||
|
|
||||||
|
/* Values to be set */
|
||||||
|
#define AM335X_VAL_USBXCTRL_SOFT_RESET HCD_BIT(0)
|
||||||
|
#define AM335X_VAL_USBXCTRL_UINT HCD_BIT(3)
|
||||||
|
|
||||||
|
#define AM335X_VAL_USBXMODE_IDDIG_MUX HCD_BIT(7)
|
||||||
|
#define AM335X_VAL_USBXMODE_IDDIG HCD_BIT(8)
|
||||||
|
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_EP0 HCD_BIT(0)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP1 HCD_BIT(1)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP2 HCD_BIT(2)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP3 HCD_BIT(3)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP4 HCD_BIT(4)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP5 HCD_BIT(5)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP6 HCD_BIT(6)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP7 HCD_BIT(7)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP8 HCD_BIT(8)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP9 HCD_BIT(9)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP10 HCD_BIT(10)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP11 HCD_BIT(11)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP12 HCD_BIT(12)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP13 HCD_BIT(13)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP14 HCD_BIT(14)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_TX_EP15 HCD_BIT(15)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP1 HCD_BIT(17)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP2 HCD_BIT(18)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP3 HCD_BIT(19)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP4 HCD_BIT(20)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP5 HCD_BIT(21)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP6 HCD_BIT(22)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP7 HCD_BIT(23)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP8 HCD_BIT(24)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP9 HCD_BIT(25)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP10 HCD_BIT(26)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP11 HCD_BIT(27)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP12 HCD_BIT(28)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP13 HCD_BIT(29)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP14 HCD_BIT(30)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX0_RX_EP15 HCD_BIT(31)
|
||||||
|
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX1_SUSPEND HCD_BIT(0)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX1_RESUME HCD_BIT(1)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX1_RESET_BABBLE HCD_BIT(2)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX1_SOF HCD_BIT(3)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED HCD_BIT(4)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED HCD_BIT(5)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX1_SRP HCD_BIT(6)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX1_VBUS HCD_BIT(7)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX1_DRVVBUS HCD_BIT(8)
|
||||||
|
#define AM335X_VAL_USBXIRQENABLEXXX1_GENERIC HCD_BIT(9)
|
||||||
|
|
||||||
|
#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_SOF HCD_BIT(3)
|
||||||
|
#define AM335X_VAL_USBXIRQSTAT1_CONNECTED HCD_BIT(4)
|
||||||
|
#define AM335X_VAL_USBXIRQSTAT1_DISCONNECTED HCD_BIT(5)
|
||||||
|
#define AM335X_VAL_USBXIRQSTAT1_SRP HCD_BIT(6)
|
||||||
|
#define AM335X_VAL_USBXIRQSTAT1_VBUS HCD_BIT(7)
|
||||||
|
#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))
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* AM335x clocking register defines *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* Clock module registers offsets */
|
||||||
|
#define AM335X_CM_PER_BASE_OFFSET 0x00u
|
||||||
|
#define AM335X_REG_CM_PER_USB0_CLKCTRL (AM335X_CM_PER_BASE_OFFSET + 28u)
|
||||||
|
|
||||||
|
/* Possible values to be set */
|
||||||
|
#define AM335X_VAL_CM_PER_USB0_CLKCTRL_MODULEMODE_ENABLE 0x2u
|
||||||
|
#define AM335X_CLKCONF_FULL_VAL 0xFFFFFFFFu
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* AM335x USB configuration structures *
|
||||||
|
*===========================================================================*/
|
||||||
|
#define AM335X_USBSS_IRQ 17
|
||||||
|
#define AM335X_USB0_IRQ 18
|
||||||
|
#define AM335X_USB1_IRQ 19
|
||||||
|
|
||||||
|
/* Hardware configuration values specific to AM335X USBSS (USB Subsystem) */
|
||||||
|
typedef struct am335x_ss_config {
|
||||||
|
|
||||||
|
void * regs; /* Points to beginning of memory mapped register space */
|
||||||
|
}
|
||||||
|
am335x_ss_config;
|
||||||
|
|
||||||
|
/* Hardware configuration values specific to AM335X USB(0,1) OTG */
|
||||||
|
typedef struct am335x_usbX_config {
|
||||||
|
|
||||||
|
void * regs; /* Points to beginning of memory mapped register space */
|
||||||
|
}
|
||||||
|
am335x_usbX_config;
|
||||||
|
|
||||||
|
/* Private data for AM335X's IRQ thread */
|
||||||
|
typedef struct am335x_irq_private {
|
||||||
|
|
||||||
|
int usb_num; /* Number of currently handled controller (0, 1) */
|
||||||
|
}
|
||||||
|
am335x_irq_private;
|
||||||
|
|
||||||
|
/* Single MUSB peripheral information */
|
||||||
|
typedef struct am335x_controller {
|
||||||
|
|
||||||
|
am335x_irq_private priv;
|
||||||
|
am335x_usbX_config usb;
|
||||||
|
musb_core_config core;
|
||||||
|
hcd_driver_state driver;
|
||||||
|
}
|
||||||
|
am335x_controller;
|
||||||
|
|
||||||
|
#define AM335X_NUM_USB_CONTROLLERS 2
|
||||||
|
#define AM335X_USB0 0
|
||||||
|
#define AM335X_USB1 1
|
||||||
|
|
||||||
|
/* Configuration values specific to AM335X... */
|
||||||
|
typedef struct am335x_config {
|
||||||
|
|
||||||
|
am335x_ss_config ss;
|
||||||
|
am335x_controller ctrl[AM335X_NUM_USB_CONTROLLERS];
|
||||||
|
}
|
||||||
|
am335x_config;
|
||||||
|
|
||||||
|
/* ...and their current holder */
|
||||||
|
static am335x_config am335x;
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Local declarations *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* Basic functionality */
|
||||||
|
static int musb_am335x_internal_init(void);
|
||||||
|
static void musb_am335x_internal_deinit(void);
|
||||||
|
|
||||||
|
/* Interrupt related */
|
||||||
|
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 *);
|
||||||
|
|
||||||
|
/* Configuration helpers */
|
||||||
|
static void musb_am335x_usb_reset(int);
|
||||||
|
static void musb_am335x_otg_enable(int);
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_am335x_init *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
musb_am335x_init(void)
|
||||||
|
{
|
||||||
|
am335x_controller * ctrl;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Initial cleanup */
|
||||||
|
memset(&am335x, 0, sizeof(am335x));
|
||||||
|
|
||||||
|
/* These registers are specific to AM335X so they are mapped here */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
/* USBSS -------------------------------------------------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Map memory for USBSS */
|
||||||
|
am335x.ss.regs = hcd_os_regs_init(AM335X_USBSS_BASE_ADDR,
|
||||||
|
AM335X_USBSS_BASE_LEN);
|
||||||
|
|
||||||
|
if (NULL == am335x.ss.regs)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
/* Attach IRQ to number */
|
||||||
|
if (EXIT_SUCCESS != hcd_os_interrupt_attach(AM335X_USBSS_IRQ,
|
||||||
|
musb_am335x_irq_init,
|
||||||
|
musb_am335x_usbss_isr,
|
||||||
|
NULL))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
#ifdef AM335X_USE_USB0
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
/* USB0 --------------------------------------------------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
ctrl = &(am335x.ctrl[AM335X_USB0]);
|
||||||
|
|
||||||
|
/* IRQ thread private data */
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* Attach IRQ to number */
|
||||||
|
if (EXIT_SUCCESS != hcd_os_interrupt_attach(AM335X_USB0_IRQ,
|
||||||
|
musb_am335x_irq_init,
|
||||||
|
musb_am335x_usbx_isr,
|
||||||
|
&(ctrl->priv)))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
/* Initialize HCD driver */
|
||||||
|
ctrl->driver.private_data = &(ctrl->core);
|
||||||
|
ctrl->driver.setup_device = musb_setup_device;
|
||||||
|
ctrl->driver.reset_device = musb_reset_device;
|
||||||
|
ctrl->driver.setup_stage = musb_setup_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->driver.out_status_stage = musb_out_status_stage;
|
||||||
|
ctrl->driver.read_data = musb_read_data;
|
||||||
|
ctrl->driver.check_error = musb_check_error;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
/* USB1 --------------------------------------------------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
{
|
||||||
|
ctrl = &(am335x.ctrl[AM335X_USB1]);
|
||||||
|
|
||||||
|
/* IRQ thread private data */
|
||||||
|
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);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Attach IRQ to number */
|
||||||
|
if (EXIT_SUCCESS != hcd_os_interrupt_attach(AM335X_USB1_IRQ,
|
||||||
|
musb_am335x_irq_init,
|
||||||
|
musb_am335x_usbx_isr,
|
||||||
|
&(ctrl->priv)))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
/* Initialize HCD driver */
|
||||||
|
ctrl->driver.private_data = &(ctrl->core);
|
||||||
|
ctrl->driver.setup_device = musb_setup_device;
|
||||||
|
ctrl->driver.reset_device = musb_reset_device;
|
||||||
|
ctrl->driver.setup_stage = musb_setup_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->driver.out_status_stage = musb_out_status_stage;
|
||||||
|
ctrl->driver.read_data = musb_read_data;
|
||||||
|
ctrl->driver.check_error = musb_check_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return musb_am335x_internal_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_am335x_deinit *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
musb_am335x_deinit(void)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
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))
|
||||||
|
USB_MSG("Failed to release USBSS mapping");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_am335x_internal_init *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
musb_am335x_internal_init(void)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Configure clocking */
|
||||||
|
if (hcd_os_clkconf(AM335X_REG_CM_PER_USB0_CLKCTRL,
|
||||||
|
AM335X_VAL_CM_PER_USB0_CLKCTRL_MODULEMODE_ENABLE,
|
||||||
|
AM335X_CLKCONF_FULL_VAL))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
/* TODO: time to stabilize? */
|
||||||
|
{
|
||||||
|
/* Sleep 25ms */
|
||||||
|
struct timespec nanotm = {0, HCD_NANOSLEEP_MSEC(25)};
|
||||||
|
nanosleep(&nanotm, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read and dump revision register */
|
||||||
|
USB_MSG("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_USBSS_IRQ);
|
||||||
|
|
||||||
|
#ifdef AM335X_USE_USB0
|
||||||
|
/* Reset controllers so we get default register values */
|
||||||
|
musb_am335x_usb_reset(AM335X_USB0);
|
||||||
|
/* Allow OS to handle previously configured USB0 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
|
||||||
|
|
||||||
|
/* Reset controllers so we get default register values */
|
||||||
|
musb_am335x_usb_reset(AM335X_USB1);
|
||||||
|
/* Allow OS to handle previously configured USB1 interrupts */
|
||||||
|
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));
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_am335x_internal_deinit *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_am335x_internal_deinit(void)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Disable all interrupts */
|
||||||
|
hcd_os_interrupt_disable(AM335X_USBSS_IRQ);
|
||||||
|
#ifdef AM335X_USE_USB0
|
||||||
|
hcd_os_interrupt_disable(AM335X_USB0_IRQ);
|
||||||
|
#endif
|
||||||
|
hcd_os_interrupt_disable(AM335X_USB1_IRQ);
|
||||||
|
|
||||||
|
/* Stop core */
|
||||||
|
#ifdef AM335X_USE_USB0
|
||||||
|
musb_core_stop(&(am335x.ctrl[AM335X_USB0].core));
|
||||||
|
#endif
|
||||||
|
musb_core_stop(&(am335x.ctrl[AM335X_USB1].core));
|
||||||
|
|
||||||
|
/* Every clkconf call should have corresponding release */
|
||||||
|
hcd_os_clkconf_release();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_am335x_irq_init *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_am335x_irq_init(void * UNUSED(unused))
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_am335x_usbss_isr *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_am335x_usbss_isr(void * UNUSED(data))
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg4 irqstat;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = am335x.ss.regs;
|
||||||
|
|
||||||
|
irqstat = HCD_RD4(r, AM335X_REG_IRQSTAT);
|
||||||
|
|
||||||
|
USB_DBG("AM335X_REG_IRQSTAT = %X", (unsigned int)irqstat);
|
||||||
|
|
||||||
|
/* Write to clear interrupt */
|
||||||
|
HCD_WR4(r, AM335X_REG_IRQSTAT, irqstat);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_am335x_usbx_isr *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_am335x_usbx_isr(void * data)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_driver_state * driver;
|
||||||
|
hcd_reg4 irqstat0;
|
||||||
|
hcd_reg4 irqstat1;
|
||||||
|
int usb_num;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Prepare locals based on USB controller number for this interrupt */
|
||||||
|
usb_num = ((am335x_irq_private*)data)->usb_num;
|
||||||
|
r = am335x.ctrl[usb_num].usb.regs;
|
||||||
|
driver = &(am335x.ctrl[usb_num].driver);
|
||||||
|
|
||||||
|
/* Read, handle and clean interrupts */
|
||||||
|
irqstat0 = HCD_RD4(r, AM335X_REG_USBXIRQSTAT0);
|
||||||
|
irqstat1 = HCD_RD4(r, AM335X_REG_USBXIRQSTAT1);
|
||||||
|
|
||||||
|
/* TODO: priority of interrupts */
|
||||||
|
if (irqstat1 & AM335X_VAL_USBXIRQSTAT1_DRVVBUS) {
|
||||||
|
USB_DBG("DRVVBUS level changed");
|
||||||
|
CLEAR_IRQ1(AM335X_VAL_USBXIRQSTAT1_DRVVBUS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
hcd_handle_event(driver);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_SUSPEND) {
|
||||||
|
USB_DBG("Unhandled SUSPEND IRQ");
|
||||||
|
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_SUSPEND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_RESUME) {
|
||||||
|
USB_DBG("Unhandled RESUME IRQ");
|
||||||
|
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_RESUME);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_RESET_BABBLE) {
|
||||||
|
USB_DBG("Unhandled RESET/BABBLE IRQ");
|
||||||
|
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_RESET_BABBLE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_SOF) {
|
||||||
|
USB_DBG("Unhandled SOF IRQ");
|
||||||
|
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_SOF);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_SRP) {
|
||||||
|
USB_DBG("Unhandled SRP IRQ");
|
||||||
|
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_SRP);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_VBUS) {
|
||||||
|
USB_DBG("Unhandled VBUS IRQ");
|
||||||
|
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_VBUS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_GENERIC) {
|
||||||
|
USB_DBG("Unhandled GENERIC IRQ");
|
||||||
|
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_GENERIC);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* When controller is correctly configured this should never happen: */
|
||||||
|
USB_MSG("Illegal value of IRQxSTAT: 0=%X 1=%X",
|
||||||
|
(unsigned int)irqstat0, (unsigned int)irqstat1);
|
||||||
|
USB_ASSERT(0, "IRQxSTAT error");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_am335x_usb_reset *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_am335x_usb_reset(int usb_num)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg4 ctrl;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = am335x.ctrl[usb_num].usb.regs;
|
||||||
|
|
||||||
|
/* Set SOFT_RESET bit and wait until it is off */
|
||||||
|
ctrl = HCD_RD4(r, AM335X_REG_USBXCTRL);
|
||||||
|
HCD_SET(ctrl, AM335X_VAL_USBXCTRL_SOFT_RESET);
|
||||||
|
HCD_WR4(r, AM335X_REG_USBXCTRL, ctrl);
|
||||||
|
while (HCD_RD4(r, AM335X_REG_USBXCTRL) &
|
||||||
|
AM335X_VAL_USBXCTRL_SOFT_RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_am335x_otg_enable *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_am335x_otg_enable(int usb_num)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg4 intreg;
|
||||||
|
hcd_reg4 mode;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = am335x.ctrl[usb_num].usb.regs;
|
||||||
|
|
||||||
|
/* Force host operation */
|
||||||
|
mode = HCD_RD4(r, AM335X_REG_USBXMODE);
|
||||||
|
HCD_SET(mode, AM335X_VAL_USBXMODE_IDDIG_MUX);
|
||||||
|
HCD_CLR(mode, AM335X_VAL_USBXMODE_IDDIG);
|
||||||
|
HCD_WR4(r, AM335X_REG_USBXMODE, mode);
|
||||||
|
|
||||||
|
/* Set all important interrupts to be handled */
|
||||||
|
intreg = HCD_RD4(r, AM335X_REG_USBXIRQENABLESET1);
|
||||||
|
HCD_SET(intreg, AM335X_VAL_USBXIRQENABLEXXX1_SUSPEND |
|
||||||
|
AM335X_VAL_USBXIRQENABLEXXX1_RESUME |
|
||||||
|
AM335X_VAL_USBXIRQENABLEXXX1_RESET_BABBLE |
|
||||||
|
/* AM335X_VAL_USBXIRQENABLEXXX1_SOF | */
|
||||||
|
AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED |
|
||||||
|
AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED |
|
||||||
|
AM335X_VAL_USBXIRQENABLEXXX1_SRP |
|
||||||
|
AM335X_VAL_USBXIRQENABLEXXX1_VBUS |
|
||||||
|
AM335X_VAL_USBXIRQENABLEXXX1_DRVVBUS |
|
||||||
|
AM335X_VAL_USBXIRQENABLEXXX1_GENERIC);
|
||||||
|
|
||||||
|
HCD_WR4(r, AM335X_REG_USBXIRQENABLESET1, intreg);
|
||||||
|
|
||||||
|
/* Set endpoint 0 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);
|
||||||
|
}
|
570
drivers/usbd/hcd/musb/musb_core.c
Executable file
570
drivers/usbd/hcd/musb/musb_core.c
Executable file
|
@ -0,0 +1,570 @@
|
||||||
|
/*
|
||||||
|
* Implementation of low level MUSB core logic (variant independent)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h> /* memcpy */
|
||||||
|
#include <time.h> /* nanosleep */
|
||||||
|
|
||||||
|
#include <usb/hcd_common.h>
|
||||||
|
#include <usb/hcd_interface.h>
|
||||||
|
#include <usb/usb_common.h>
|
||||||
|
|
||||||
|
#include "musb_core.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 void musb_clear_statuspkt(void *);
|
||||||
|
static int musb_get_count(void *);
|
||||||
|
static void musb_read_fifo(void *, hcd_reg1 *, int, int);
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* *
|
||||||
|
* MUSB core implementation *
|
||||||
|
* *
|
||||||
|
*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_set_state *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_set_state(musb_core_config * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg1 idx;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = cfg->regs;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* Use device with address 'cfg->addr' */
|
||||||
|
HCD_WR2(r, MUSB_REG_RXFUNCADDR, cfg->addr);
|
||||||
|
HCD_WR2(r, MUSB_REG_TXFUNCADDR, cfg->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_check_rxpktrdy *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
musb_check_rxpktrdy(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg2 host_csr0;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_in_stage_cleanup *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_in_stage_cleanup(void * cfg)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
musb_clear_rxpktrdy(cfg);
|
||||||
|
musb_clear_statuspkt(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_clear_rxpktrdy *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_clear_rxpktrdy(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg2 host_csr0;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_clear_statuspkt *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_clear_statuspkt(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg2 host_csr0;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* 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 STATUSPKT to signal status packet completion */
|
||||||
|
HCD_CLR(host_csr0, MUSB_VAL_HOST_CSR0_STATUSPKT);
|
||||||
|
HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_get_count *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
musb_get_count(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* Set EP and device address to be used in this command */
|
||||||
|
musb_set_state((musb_core_config *)cfg);
|
||||||
|
|
||||||
|
/* Reserved part returns zero so no need to generalize
|
||||||
|
* this return for MUSB_REG_RXCOUNT */
|
||||||
|
return (int)(HCD_RD2(r, MUSB_REG_COUNT0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_read_fifo *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
musb_read_fifo(void * cfg, hcd_reg1 * output, int size, int fifo_num)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg4 * word;
|
||||||
|
hcd_reg4 copy_buf[HCD_COPYBUF_WORDS];
|
||||||
|
hcd_addr fifo_addr;
|
||||||
|
int limit;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
USB_ASSERT((fifo_num >= 0) && (fifo_num <= 4), "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);
|
||||||
|
|
||||||
|
/* Read full words from MUSB FIFO */
|
||||||
|
while (size > 0) {
|
||||||
|
/* Largest amount of bytes that can be copied at a time */
|
||||||
|
limit = (size < HCD_COPYBUF_BYTES) ? size : HCD_COPYBUF_BYTES;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* Copy and shift */
|
||||||
|
memcpy(output, copy_buf, limit);
|
||||||
|
output += limit;
|
||||||
|
size -= limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_core_start *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
musb_core_start(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg1 devctl;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* Enable all interrupts valid for host */
|
||||||
|
HCD_WR1(r, MUSB_REG_INTRUSBE,
|
||||||
|
MUSB_VAL_INTRUSBE_SUSPEND |
|
||||||
|
MUSB_VAL_INTRUSBE_RESUME |
|
||||||
|
MUSB_VAL_INTRUSBE_RESET_BABBLE |
|
||||||
|
/* MUSB_VAL_INTRUSBE_SOF | */
|
||||||
|
MUSB_VAL_INTRUSBE_CONN |
|
||||||
|
MUSB_VAL_INTRUSBE_DISCON |
|
||||||
|
MUSB_VAL_INTRUSBE_SESSREQ |
|
||||||
|
MUSB_VAL_INTRUSBE_VBUSERR);
|
||||||
|
|
||||||
|
/* Start session */
|
||||||
|
devctl = HCD_RD1(r, MUSB_REG_DEVCTL);
|
||||||
|
HCD_SET(devctl, MUSB_VAL_DEVCTL_SESSION);
|
||||||
|
HCD_WR1(r, MUSB_REG_DEVCTL, devctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_core_stop *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
musb_core_stop(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg1 devctl;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* TODO: add hardware interrupt disable */
|
||||||
|
|
||||||
|
/* Stop session */
|
||||||
|
devctl = HCD_RD1(r, MUSB_REG_DEVCTL);
|
||||||
|
HCD_CLR(devctl, MUSB_VAL_DEVCTL_SESSION);
|
||||||
|
HCD_WR1(r, MUSB_REG_DEVCTL, devctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* 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_setup_device *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
musb_setup_device(void * cfg, hcd_reg1 ep, hcd_reg1 addr)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Assign */
|
||||||
|
((musb_core_config *)cfg)->ep = ep;
|
||||||
|
((musb_core_config *)cfg)->addr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_reset_device *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
musb_reset_device(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg1 power;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* Write reset bit and high speed negotiation wait for at least
|
||||||
|
* 20ms for reset, clear reset bit and wait for device */
|
||||||
|
power = HCD_RD1(r, MUSB_REG_POWER);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_setup_stage *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
musb_setup_stage(void * cfg, hcd_ctrlrequest * setup)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
char * setup_byte;
|
||||||
|
hcd_reg2 host_csr0;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
setup_byte = (char*)setup;
|
||||||
|
|
||||||
|
/* Set EP and device address to be used in this command */
|
||||||
|
musb_set_state((musb_core_config *)cfg);
|
||||||
|
|
||||||
|
/* TODO: check for ongoing transmission */
|
||||||
|
|
||||||
|
/* Put USB setup data into corresponding 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)]));
|
||||||
|
|
||||||
|
/* Get control status register for EP 0 */
|
||||||
|
host_csr0 = HCD_RD2(r, MUSB_REG_HOST_CSR0);
|
||||||
|
|
||||||
|
/* Send actual packet from FIFO */
|
||||||
|
HCD_SET(host_csr0, MUSB_VAL_HOST_CSR0_TXPKTRDY |
|
||||||
|
MUSB_VAL_HOST_CSR0_SETUPPKT);
|
||||||
|
|
||||||
|
HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_in_data_stage *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
musb_in_data_stage(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg2 host_csr0;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* Request IN DATA stage */
|
||||||
|
HCD_SET(host_csr0, MUSB_VAL_HOST_CSR0_REQPKT);
|
||||||
|
HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_out_data_stage *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
musb_out_data_stage(void * cfg)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_in_status_stage *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
musb_in_status_stage(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg2 host_csr0;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* Request IN STATUS stage */
|
||||||
|
HCD_SET(host_csr0, MUSB_VAL_HOST_CSR0_REQPKT |
|
||||||
|
MUSB_VAL_HOST_CSR0_STATUSPKT);
|
||||||
|
|
||||||
|
HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_out_status_stage *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
musb_out_status_stage(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg2 host_csr0;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* Request OUT STATUS stage */
|
||||||
|
HCD_SET(host_csr0, MUSB_VAL_HOST_CSR0_TXPKTRDY |
|
||||||
|
MUSB_VAL_HOST_CSR0_STATUSPKT);
|
||||||
|
|
||||||
|
HCD_WR2(r, MUSB_REG_HOST_CSR0, host_csr0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_read_data *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
musb_read_data(void * cfg, hcd_reg1 * buffer, int buffer_num)
|
||||||
|
{
|
||||||
|
int count0;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Check if anything received at all */
|
||||||
|
if (EXIT_SUCCESS != musb_check_rxpktrdy(cfg)) {
|
||||||
|
USB_MSG("RXPKTRDY not set when receiving");
|
||||||
|
return HCD_READ_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Number of bytes received at EP0 */
|
||||||
|
count0 = musb_get_count(cfg);
|
||||||
|
|
||||||
|
/* Read from given FIFO */
|
||||||
|
if ((NULL != buffer) && (count0 > 0))
|
||||||
|
musb_read_fifo(cfg, buffer, count0, buffer_num);
|
||||||
|
|
||||||
|
/* Cleanup after reading */
|
||||||
|
musb_in_stage_cleanup(cfg);
|
||||||
|
|
||||||
|
return count0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* musb_check_error *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
musb_check_error(void * cfg)
|
||||||
|
{
|
||||||
|
void * r;
|
||||||
|
hcd_reg2 host_csr0;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
r = ((musb_core_config *)cfg)->regs;
|
||||||
|
|
||||||
|
/* 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 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
47
drivers/usbd/hcd/musb/musb_core.h
Executable file
47
drivers/usbd/hcd/musb/musb_core.h
Executable file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Interface of low level MUSB core logic (variant independent)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MUSB_CORE_H_
|
||||||
|
#define _MUSB_CORE_H_
|
||||||
|
|
||||||
|
#include <usb/hcd_common.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Types and constants *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* Structure to hold Mentor USB core configuration
|
||||||
|
* May be more than one on a single chip
|
||||||
|
* Should be initialized by MUSB's variant specific code (like AM335x) */
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
void * regs; /* Points to beginning of memory mapped registers */
|
||||||
|
hcd_reg1 ep; /* Currently used endpoint */
|
||||||
|
hcd_reg1 addr; /* Currently used address */
|
||||||
|
}
|
||||||
|
musb_core_config;
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Function prototypes *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* 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 *);
|
||||||
|
void musb_setup_stage(void *, hcd_ctrlrequest *);
|
||||||
|
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 *);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !_MUSB_CORE_H_ */
|
126
drivers/usbd/hcd/musb/musb_regs.h
Executable file
126
drivers/usbd/hcd/musb/musb_regs.h
Executable file
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Common MUSB core registers definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _MUSB_REGS_H_
|
||||||
|
#define _MUSB_REGS_H_
|
||||||
|
|
||||||
|
#include <usb/hcd_common.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* MUSB core register offsets *
|
||||||
|
*===========================================================================*/
|
||||||
|
#define MUSB_REG_FADDR 0x00u
|
||||||
|
#define MUSB_REG_POWER 0x01u
|
||||||
|
#define MUSB_REG_INTRTX 0x02u
|
||||||
|
#define MUSB_REG_INTRRX 0x04u
|
||||||
|
#define MUSB_REG_INTRTXE 0x06u
|
||||||
|
#define MUSB_REG_INTRRXE 0x08u
|
||||||
|
#define MUSB_REG_INTRUSB 0x0Au
|
||||||
|
#define MUSB_REG_INTRUSBE 0x0Bu
|
||||||
|
#define MUSB_REG_FRAME 0x0Cu
|
||||||
|
#define MUSB_REG_INDEX 0x0Eu
|
||||||
|
#define MUSB_REG_TESTMODE 0x0Fu
|
||||||
|
|
||||||
|
/* Proxy registers for endpoint configuration,
|
||||||
|
* that correspond to specific endpoint's register space
|
||||||
|
* selected with MUSB_REG_INDEX */
|
||||||
|
#define MUSB_REG_TXMAXP 0x10u
|
||||||
|
#define MUSB_REG_PERI_CSR0 0x12u
|
||||||
|
#define MUSB_REG_HOST_CSR0 MUSB_REG_PERI_CSR0
|
||||||
|
#define MUSB_REG_PERI_TXCSR MUSB_REG_PERI_CSR0
|
||||||
|
#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_COUNT0 0x18u
|
||||||
|
#define MUSB_REG_RXCOUNT MUSB_COUNT0
|
||||||
|
#define MUSB_REG_HOST_TYPE0 0x1Au
|
||||||
|
#define MUSB_REG_HOST_TXTYPE MUSB_HOST_TYPE0
|
||||||
|
#define MUSB_REG_HOST_NAKLIMIT0 0x1Bu
|
||||||
|
#define MUSB_REG_HOST_TXINTERVAL MUSB_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_FIFO2 0x28u
|
||||||
|
#define MUSB_REG_FIFO3 0x2Cu
|
||||||
|
#define MUSB_REG_FIFO4 0x30u
|
||||||
|
#define MUSB_REG_FIFO_LEN 0x04u
|
||||||
|
|
||||||
|
#define MUSB_REG_DEVCTL 0x60u
|
||||||
|
#define MUSB_REG_TXFIFOSZ 0x62u
|
||||||
|
#define MUSB_REG_RXFIFOSZ 0x63u
|
||||||
|
#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
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* MUSB core register values *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* POWER */
|
||||||
|
#define MUSB_VAL_POWER_ENSUSPM HCD_BIT(0)
|
||||||
|
#define MUSB_VAL_POWER_SUSPENDM HCD_BIT(1)
|
||||||
|
#define MUSB_VAL_POWER_RESUME HCD_BIT(2)
|
||||||
|
#define MUSB_VAL_POWER_RESET HCD_BIT(3)
|
||||||
|
#define MUSB_VAL_POWER_HSMODE HCD_BIT(4)
|
||||||
|
#define MUSB_VAL_POWER_HSEN HCD_BIT(5)
|
||||||
|
#define MUSB_VAL_POWER_SOFTCONN HCD_BIT(6)
|
||||||
|
#define MUSB_VAL_POWER_ISOUPDATE HCD_BIT(7)
|
||||||
|
|
||||||
|
/* DEVCTL */
|
||||||
|
#define MUSB_VAL_DEVCTL_SESSION HCD_BIT(0)
|
||||||
|
#define MUSB_VAL_DEVCTL_HOSTREQ HCD_BIT(1)
|
||||||
|
#define MUSB_VAL_DEVCTL_HOSTMODE HCD_BIT(2)
|
||||||
|
#define MUSB_VAL_DEVCTL_VBUS_1 HCD_BIT(3)
|
||||||
|
#define MUSB_VAL_DEVCTL_VBUS_2 HCD_BIT(4)
|
||||||
|
#define MUSB_VAL_DEVCTL_VBUS_3 (HCD_BIT(3) | HCD_BIT(4))
|
||||||
|
#define MUSB_VAL_DEVCTL_LSDEV HCD_BIT(5)
|
||||||
|
#define MUSB_VAL_DEVCTL_FSDEV HCD_BIT(6)
|
||||||
|
#define MUSB_VAL_DEVCTL_BDEVICE HCD_BIT(7)
|
||||||
|
|
||||||
|
/* INTRUSBE */
|
||||||
|
#define MUSB_VAL_INTRUSBE_SUSPEND HCD_BIT(0)
|
||||||
|
#define MUSB_VAL_INTRUSBE_RESUME HCD_BIT(1)
|
||||||
|
#define MUSB_VAL_INTRUSBE_RESET_BABBLE HCD_BIT(2)
|
||||||
|
#define MUSB_VAL_INTRUSBE_SOF HCD_BIT(3)
|
||||||
|
#define MUSB_VAL_INTRUSBE_CONN HCD_BIT(4)
|
||||||
|
#define MUSB_VAL_INTRUSBE_DISCON HCD_BIT(5)
|
||||||
|
#define MUSB_VAL_INTRUSBE_SESSREQ HCD_BIT(6)
|
||||||
|
#define MUSB_VAL_INTRUSBE_VBUSERR HCD_BIT(7)
|
||||||
|
|
||||||
|
/* HOST_TYPE0 */
|
||||||
|
#define MUSB_VAL_HOST_TYPE0_MASK (HCD_BIT(6) | HCD_BIT(7))
|
||||||
|
#define MUSB_VAL_HOST_TYPE0_HIGH_SPEED HCD_BIT(6)
|
||||||
|
#define MUSB_VAL_HOST_TYPE0_FULL_SPEED HCD_BIT(7)
|
||||||
|
#define MUSB_VAL_HOST_TYPE0_LOW_SPEED (HCD_BIT(6) | HCD_BIT(7))
|
||||||
|
|
||||||
|
/* INTRTXE */
|
||||||
|
#define MUSB_VAL_INTRTXE_EP0 HCD_BIT(0)
|
||||||
|
#define MUSB_VAL_INTRTXE_EP1TX HCD_BIT(1)
|
||||||
|
#define MUSB_VAL_INTRTXE_EP2TX HCD_BIT(2)
|
||||||
|
#define MUSB_VAL_INTRTXE_EP3TX HCD_BIT(3)
|
||||||
|
#define MUSB_VAL_INTRTXE_EP4TX HCD_BIT(4)
|
||||||
|
|
||||||
|
/* HOST_CSR0 */
|
||||||
|
#define MUSB_VAL_HOST_CSR0_RXPKTRDY HCD_BIT(0)
|
||||||
|
#define MUSB_VAL_HOST_CSR0_TXPKTRDY HCD_BIT(1)
|
||||||
|
#define MUSB_VAL_HOST_CSR0_RXSTALL HCD_BIT(2)
|
||||||
|
#define MUSB_VAL_HOST_CSR0_SETUPPKT HCD_BIT(3)
|
||||||
|
#define MUSB_VAL_HOST_CSR0_ERROR HCD_BIT(4)
|
||||||
|
#define MUSB_VAL_HOST_CSR0_REQPKT HCD_BIT(5)
|
||||||
|
#define MUSB_VAL_HOST_CSR0_STATUSPKT HCD_BIT(6)
|
||||||
|
#define MUSB_VAL_HOST_CSR0_NAK_TIMEOUT HCD_BIT(7)
|
||||||
|
#define MUSB_VAL_HOST_CSR0_FLUSHFIFO HCD_BIT(8)
|
||||||
|
|
||||||
|
#endif /* !_MUSB_REGS_H_ */
|
214
drivers/usbd/include/usb/hcd_common.h
Executable file
214
drivers/usbd/include/usb/hcd_common.h
Executable file
|
@ -0,0 +1,214 @@
|
||||||
|
/*
|
||||||
|
* Contains commonly used types and procedures, for HCD handling/initialization
|
||||||
|
* If possible, everything OS specific (IPC, virtual memory...) should be here
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HCD_COMMON_H_
|
||||||
|
#define _HCD_COMMON_H_
|
||||||
|
|
||||||
|
#include <ddekit/thread.h>
|
||||||
|
#include <ddekit/semaphore.h>
|
||||||
|
#include <ddekit/usb.h>
|
||||||
|
|
||||||
|
#include <minix/usb.h> /* for setup structures */
|
||||||
|
#include <minix/usb_ch9.h> /* for descriptor structures */
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* USB register handling defines *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* Helper type used for register bitwise access */
|
||||||
|
#define HCD_BIT(num) (0x01u << (num))
|
||||||
|
|
||||||
|
/* Unsigned type that can hold all possible addresses */
|
||||||
|
typedef unsigned long hcd_addr;
|
||||||
|
|
||||||
|
/* Register types */
|
||||||
|
typedef unsigned long hcd_reg4;
|
||||||
|
typedef unsigned short hcd_reg2;
|
||||||
|
typedef unsigned char hcd_reg1;
|
||||||
|
|
||||||
|
/* For register dereferencing */
|
||||||
|
#define _HCD_REG4 hcd_reg4 * volatile
|
||||||
|
#define _HCD_REG2 hcd_reg2 * volatile
|
||||||
|
#define _HCD_REG1 hcd_reg1 * volatile
|
||||||
|
|
||||||
|
/* Scalar address to dereference */
|
||||||
|
#define _HCD_ADDR(base, off) (((hcd_addr)(base))+(off))
|
||||||
|
|
||||||
|
/* Defines for fixed size register access
|
||||||
|
* May cause unaligned memory access */
|
||||||
|
#define HCD_WR4(base, off, val) (*((_HCD_REG4)_HCD_ADDR(base, off)) = (val))
|
||||||
|
#define HCD_WR2(base, off, val) (*((_HCD_REG2)_HCD_ADDR(base, off)) = (val))
|
||||||
|
#define HCD_WR1(base, off, val) (*((_HCD_REG1)_HCD_ADDR(base, off)) = (val))
|
||||||
|
#define HCD_RD4(base, off) (*((_HCD_REG4)_HCD_ADDR(base, off)))
|
||||||
|
#define HCD_RD2(base, off) (*((_HCD_REG2)_HCD_ADDR(base, off)))
|
||||||
|
#define HCD_RD1(base, off) (*((_HCD_REG1)_HCD_ADDR(base, off)))
|
||||||
|
|
||||||
|
/* Other useful defines */
|
||||||
|
#define HCD_SET(val, bits) ((val)|=(bits))
|
||||||
|
#define HCD_CLR(val, bits) ((val)&=~(bits))
|
||||||
|
|
||||||
|
/* Alignment safe conversion from 'bytes' array to a word */
|
||||||
|
#define HCD_8TO32(bytes) (((bytes)[0]) | \
|
||||||
|
(((bytes)[1])<<8) | \
|
||||||
|
(((bytes)[2])<<16) | \
|
||||||
|
(((bytes)[3])<<24))
|
||||||
|
|
||||||
|
/* Convert type's 'sizeof' to 4-byte words count */
|
||||||
|
#define HCD_SIZEOF_TO_4(type) ((sizeof(type)+3)/4)
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* 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;
|
||||||
|
typedef usb_interface_descriptor_t hcd_interface_descriptor;
|
||||||
|
typedef usb_endpoint_descriptor_t hcd_endpoint_descriptor;
|
||||||
|
typedef usb_string_descriptor_t hcd_string_descriptor;
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* HCD descriptor tree types *
|
||||||
|
*===========================================================================*/
|
||||||
|
typedef struct hcd_endpoint {
|
||||||
|
|
||||||
|
hcd_endpoint_descriptor descriptor;
|
||||||
|
}
|
||||||
|
hcd_endpoint;
|
||||||
|
|
||||||
|
typedef struct hcd_interface {
|
||||||
|
|
||||||
|
hcd_interface_descriptor descriptor;
|
||||||
|
hcd_endpoint * endpoint;
|
||||||
|
int num_endpoints;
|
||||||
|
}
|
||||||
|
hcd_interface;
|
||||||
|
|
||||||
|
typedef struct hcd_configuration {
|
||||||
|
|
||||||
|
hcd_config_descriptor descriptor;
|
||||||
|
hcd_interface * interface;
|
||||||
|
int num_interfaces;
|
||||||
|
}
|
||||||
|
hcd_configuration;
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* HCD device helper types *
|
||||||
|
*===========================================================================*/
|
||||||
|
typedef void (*hcd_thread_function)(void *);
|
||||||
|
typedef ddekit_thread_t hcd_thread;
|
||||||
|
typedef ddekit_sem_t hcd_lock;
|
||||||
|
typedef struct hcd_driver_state hcd_driver_state;
|
||||||
|
typedef struct ddekit_usb_urb hcd_urb;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
HCD_STATE_DISCONNECTED = 0, /* default for initialization */
|
||||||
|
HCD_STATE_CONNECTION_PENDING,
|
||||||
|
HCD_STATE_CONNECTED
|
||||||
|
}
|
||||||
|
hcd_state;
|
||||||
|
|
||||||
|
/* 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_thread * thread;
|
||||||
|
hcd_lock * lock;
|
||||||
|
hcd_urb * urb;
|
||||||
|
void * data;
|
||||||
|
|
||||||
|
hcd_device_descriptor device_desc;
|
||||||
|
hcd_configuration config_tree;
|
||||||
|
hcd_reg1 max_packet_size;
|
||||||
|
|
||||||
|
hcd_state state;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Other definitions *
|
||||||
|
*===========================================================================*/
|
||||||
|
#define HCD_NANOSLEEP_SEC(sec) ((sec) * 1000000000)
|
||||||
|
#define HCD_NANOSLEEP_MSEC(msec) ((msec) * 1000000)
|
||||||
|
#define HCD_NANOSLEEP_USEC(usec) ((usec) * 1000)
|
||||||
|
|
||||||
|
/* Default USB communication parameters */
|
||||||
|
#define HCD_DEFAULT_EP 0x00
|
||||||
|
#define HCD_DEFAULT_ADDR 0x00
|
||||||
|
|
||||||
|
/* TODO: one device */
|
||||||
|
#define HCD_ATTACHED_ADDR 0x01
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Operating system specific *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* Generic method for registering interrupts */
|
||||||
|
int hcd_os_interrupt_attach(int irq, void (*init)(void *),
|
||||||
|
void (*isr)(void *), void *priv);
|
||||||
|
|
||||||
|
/* Generic method for unregistering interrupts */
|
||||||
|
void hcd_os_interrupt_detach(int);
|
||||||
|
|
||||||
|
/* Generic method for enabling interrupts */
|
||||||
|
void hcd_os_interrupt_enable(int);
|
||||||
|
|
||||||
|
/* Generic method for disabling interrupts */
|
||||||
|
void hcd_os_interrupt_disable(int);
|
||||||
|
|
||||||
|
/* Returns pointer to memory mapped for given arguments */
|
||||||
|
void * hcd_os_regs_init(unsigned long, unsigned long);
|
||||||
|
|
||||||
|
/* Unregisters mapped memory */
|
||||||
|
int hcd_os_regs_deinit(unsigned long, unsigned long);
|
||||||
|
|
||||||
|
/* Configure clocking */
|
||||||
|
int hcd_os_clkconf(unsigned long, unsigned long, unsigned long);
|
||||||
|
|
||||||
|
/* Release clocking */
|
||||||
|
int hcd_os_clkconf_release(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Device handling calls *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* Initializes device threading on connection */
|
||||||
|
int hcd_connect_device(hcd_device_state *, hcd_thread_function);
|
||||||
|
|
||||||
|
/* Cleans after device disconnection */
|
||||||
|
void hcd_disconnect_device(hcd_device_state *);
|
||||||
|
|
||||||
|
/* Locks device thread until 'hcd_device_continue' */
|
||||||
|
void hcd_device_wait(hcd_device_state *);
|
||||||
|
|
||||||
|
/* Unlocks device thread halted by 'hcd_device_wait' */
|
||||||
|
void hcd_device_continue(hcd_device_state *);
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Descriptor tree calls *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* Creates descriptor tree based on given buffer */
|
||||||
|
int hcd_buffer_to_tree(hcd_reg1 *, int, hcd_configuration *);
|
||||||
|
|
||||||
|
/* Frees descriptor tree */
|
||||||
|
void hcd_tree_cleanup(hcd_configuration *);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !_HCD_COMMON_H_ */
|
18
drivers/usbd/include/usb/hcd_ddekit.h
Executable file
18
drivers/usbd/include/usb/hcd_ddekit.h
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Whatever must be known to DDEkit callers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HCD_DDEKIT_H_
|
||||||
|
#define _HCD_DDEKIT_H_
|
||||||
|
|
||||||
|
#include <usb/hcd_common.h>
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* External declarations *
|
||||||
|
*===========================================================================*/
|
||||||
|
void hcd_connect_cb(hcd_device_state *);
|
||||||
|
void hcd_disconnect_cb(hcd_device_state *);
|
||||||
|
void hcd_completion_cb(void *);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !_HCD_DDEKIT_H_ */
|
73
drivers/usbd/include/usb/hcd_interface.h
Executable file
73
drivers/usbd/include/usb/hcd_interface.h
Executable file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Interface for HCD
|
||||||
|
*
|
||||||
|
* This file holds prototypes that must be implemented by HCD
|
||||||
|
* and event call that should be called when interrupt occurred
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HCD_INTERFACE_H_
|
||||||
|
#define _HCD_INTERFACE_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 *
|
||||||
|
*===========================================================================*/
|
||||||
|
#define HCD_READ_ERR -1
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* HCD driver structure to be filled
|
||||||
|
*===========================================================================*/
|
||||||
|
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 *);
|
||||||
|
|
||||||
|
/* 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 handling routine *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* Handle asynchronous event
|
||||||
|
* This must be called in case of specific HCD interrupts listed above */
|
||||||
|
void hcd_handle_event(hcd_driver_state *);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !_HCD_INTERFACE_H_ */
|
20
drivers/usbd/include/usb/hcd_platforms.h
Executable file
20
drivers/usbd/include/usb/hcd_platforms.h
Executable file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Externally visible interface for possible USB controllers
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HCD_PLATFORMS_H_
|
||||||
|
#define _HCD_PLATFORMS_H_
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* MUSB *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* ----- AM335X ----- */
|
||||||
|
int musb_am335x_init(void);
|
||||||
|
void musb_am335x_deinit(void);
|
||||||
|
/* ----- AM/DM37X ----- */
|
||||||
|
int musb_dm37x_init(void);
|
||||||
|
void musb_dm37x_deinit(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !_HCD_PLATFORMS_H_ */
|
65
drivers/usbd/include/usb/usb_common.h
Executable file
65
drivers/usbd/include/usb/usb_common.h
Executable file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Whatever is commonly used throughout USB code
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _USB_COMMON_H_
|
||||||
|
#define _USB_COMMON_H_
|
||||||
|
|
||||||
|
/* For commonly used: NULL, EXIT_*, and stuff like that */
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Current printf implementation for dumping important messages */
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
/* TODO: should be elsewhere */
|
||||||
|
#define DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Standard output message *
|
||||||
|
*===========================================================================*/
|
||||||
|
#define USB_MSG(fmt, ...) \
|
||||||
|
do { \
|
||||||
|
printf("USBD: "); \
|
||||||
|
printf(fmt, ##__VA_ARGS__); \
|
||||||
|
printf("\n"); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Debug helpers *
|
||||||
|
*===========================================================================*/
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define DEBUG_DUMP \
|
||||||
|
do { \
|
||||||
|
printf("USBD (DEBUG %s)\n", __func__); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define USB_DBG(fmt, ...) \
|
||||||
|
do { \
|
||||||
|
printf("USBD (DEBUG %s): ", __func__); \
|
||||||
|
printf(fmt, ##__VA_ARGS__); \
|
||||||
|
printf("\n"); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define DEBUG_DUMP
|
||||||
|
#define USB_DBG(fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Assert for USB code *
|
||||||
|
*===========================================================================*/
|
||||||
|
#define USB_ASSERT(cond, otherwise) \
|
||||||
|
do { \
|
||||||
|
if(!(cond)) { \
|
||||||
|
USB_MSG("ERROR - "otherwise); \
|
||||||
|
exit(EXIT_FAILURE); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !_USB_COMMON_H_ */
|
24
drivers/usbd/include/usb/usbd_interface.h
Executable file
24
drivers/usbd/include/usb/usbd_interface.h
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Interface for USBD
|
||||||
|
*
|
||||||
|
* This file holds prototypes that must be implemented by platform
|
||||||
|
* specific USBD
|
||||||
|
*
|
||||||
|
* Must be implemented once per USBD but may be used for multiple
|
||||||
|
* controllers at a time when platform has more than one HCD
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _USBD_INTERFACE_H_
|
||||||
|
#define _USBD_INTERFACE_H_
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Prototypes to be implemented *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* Must set up HCDs in general and interrupts to
|
||||||
|
* be handled by DDEkit in particular */
|
||||||
|
int usbd_init_hcd(void);
|
||||||
|
|
||||||
|
/* Should clean whatever usbd_init_hcd used */
|
||||||
|
void usbd_deinit_hcd(void);
|
||||||
|
|
||||||
|
#endif /* !_USBD_INTERFACE_H_ */
|
14
drivers/usbd/usbd.conf
Executable file
14
drivers/usbd/usbd.conf
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
service usbd
|
||||||
|
{
|
||||||
|
system
|
||||||
|
PRIVCTL
|
||||||
|
UMAP
|
||||||
|
IRQCTL
|
||||||
|
;
|
||||||
|
irq
|
||||||
|
92 #BeagleXM
|
||||||
|
17 #BeagleBoneWhite
|
||||||
|
18 #BeagleBoneWhite
|
||||||
|
19 #BeagleBoneWhite
|
||||||
|
;
|
||||||
|
};
|
Loading…
Reference in a new issue