Much USB code for ARM USB support
Written by JP Embedded. Host controller (HCD), mass storage, and hub drivers. Change-Id: I4237cf7aeb4a1c0205a1876593a9cc67ef3d577e
This commit is contained in:
parent
bad58c9c51
commit
2d64210c1d
41 changed files with 2905 additions and 427 deletions
|
@ -82,6 +82,7 @@
|
||||||
./etc/devmand/scripts minix-sys
|
./etc/devmand/scripts minix-sys
|
||||||
./etc/devmand/scripts/block minix-sys
|
./etc/devmand/scripts/block minix-sys
|
||||||
./etc/devmand/scripts/singlechar minix-sys
|
./etc/devmand/scripts/singlechar minix-sys
|
||||||
|
./etc/devmand/usb_hub.cfg minix-sys
|
||||||
./etc/devmand/usb_storage.cfg minix-sys
|
./etc/devmand/usb_storage.cfg minix-sys
|
||||||
./etc/gettytab minix-sys
|
./etc/gettytab minix-sys
|
||||||
./etc/group minix-sys
|
./etc/group minix-sys
|
||||||
|
@ -116,6 +117,7 @@
|
||||||
./etc/system.conf minix-sys
|
./etc/system.conf minix-sys
|
||||||
./etc/system.conf.d minix-sys
|
./etc/system.conf.d minix-sys
|
||||||
./etc/system.conf.d/ipc minix-sys
|
./etc/system.conf.d/ipc minix-sys
|
||||||
|
./etc/system.conf.d/usb_hub minix-sys
|
||||||
./etc/system.conf.d/usb_storage minix-sys
|
./etc/system.conf.d/usb_storage minix-sys
|
||||||
./etc/termcap minix-sys
|
./etc/termcap minix-sys
|
||||||
./etc/ttys minix-sys
|
./etc/ttys minix-sys
|
||||||
|
@ -172,6 +174,7 @@
|
||||||
./service/sched minix-sys
|
./service/sched minix-sys
|
||||||
./service/tty minix-sys
|
./service/tty minix-sys
|
||||||
./service/uds minix-sys
|
./service/uds minix-sys
|
||||||
|
./service/usb_hub minix-sys
|
||||||
./service/usb_storage minix-sys
|
./service/usb_storage minix-sys
|
||||||
./service/vfs minix-sys
|
./service/vfs minix-sys
|
||||||
./service/vm minix-sys
|
./service/vm minix-sys
|
||||||
|
|
|
@ -430,6 +430,7 @@ install-etc-files-safe: .PHONY .MAKE check_DESTDIR MAKEDEV
|
||||||
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/ ${DESTDIR}/usr/lib/ crontab \
|
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/ ${DESTDIR}/usr/lib/ crontab \
|
||||||
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/ ${DESTDIR}/etc/ system.conf \
|
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/ ${DESTDIR}/etc/ system.conf \
|
||||||
${BINOWN} ${BINGRP} ${NONBINMODE} ${NETBSDSRCDIR}/etc/usr/ ${DESTDIR}/usr/ Makefile \
|
${BINOWN} ${BINGRP} ${NONBINMODE} ${NETBSDSRCDIR}/etc/usr/ ${DESTDIR}/usr/ Makefile \
|
||||||
|
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/devmand/ ${DESTDIR}/etc/devmand/ usb_hub.cfg \
|
||||||
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/devmand/ ${DESTDIR}/etc/devmand/ usb_storage.cfg \
|
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/devmand/ ${DESTDIR}/etc/devmand/ usb_storage.cfg \
|
||||||
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/devmand/scripts/ ${DESTDIR}/etc/devmand/scripts/ block \
|
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/devmand/scripts/ ${DESTDIR}/etc/devmand/scripts/ block \
|
||||||
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/devmand/scripts/ ${DESTDIR}/etc/devmand/scripts/ singlechar \
|
${BINOWN} ${BINGRP} ${BINMODE} ${NETBSDSRCDIR}/etc/devmand/scripts/ ${DESTDIR}/etc/devmand/scripts/ singlechar \
|
||||||
|
|
8
etc/devmand/usb_hub.cfg
Normal file
8
etc/devmand/usb_hub.cfg
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
usb_driver usb_hub
|
||||||
|
{
|
||||||
|
binary = /service/usb_hub;
|
||||||
|
id {
|
||||||
|
bInterfaceClass = 0x09;
|
||||||
|
}
|
||||||
|
devprefix = usb_hub;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
usb_driver usb_storage
|
usb_driver usb_storage
|
||||||
{
|
{
|
||||||
binary = /usr/sbin/usb_storage;
|
binary = /service/usb_storage;
|
||||||
id {
|
id {
|
||||||
bInterfaceClass = 0x08;
|
bInterfaceClass = 0x08;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,6 @@
|
||||||
SUBDIR+= usbd
|
SUBDIR+= usbd
|
||||||
.endif # ${MACHINE_ARCH} == "earm"
|
.endif # ${MACHINE_ARCH} == "earm"
|
||||||
|
|
||||||
SUBDIR+= usb_storage
|
SUBDIR+= usb_storage usb_hub
|
||||||
|
|
||||||
.include <bsd.subdir.mk>
|
.include <bsd.subdir.mk>
|
||||||
|
|
16
minix/drivers/usb/usb_hub/Makefile
Normal file
16
minix/drivers/usb/usb_hub/Makefile
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Makefile for USB hub driver
|
||||||
|
PROG=usb_hub
|
||||||
|
SRCS=usb_hub.c urb_helper.c
|
||||||
|
|
||||||
|
FILES=$(PROG).conf
|
||||||
|
FILESNAME=$(PROG)
|
||||||
|
FILESDIR=/etc/system.conf.d
|
||||||
|
|
||||||
|
DPADD+=${LIBDDEKIT_USB_CLIENT} ${LIBDDEKIT} ${LIBUSB} ${LIBSYS} ${LIBMINLIB}
|
||||||
|
LDADD+=-lddekit_usb_client -lddekit -lusb -lsys
|
||||||
|
|
||||||
|
#For easier debugging, uncomment:
|
||||||
|
#LDADD+=-Wl,-Ttext=0x800000
|
||||||
|
#CPPFLAGS+=-DHUB_DEBUG
|
||||||
|
|
||||||
|
.include <minix.service.mk>
|
35
minix/drivers/usb/usb_hub/common.h
Normal file
35
minix/drivers/usb/usb_hub/common.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Whatever is commonly used in hub driver, should be here
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _COMMON_H_
|
||||||
|
#define _COMMON_H_
|
||||||
|
|
||||||
|
/*---------------------------*
|
||||||
|
* commonly used headers: *
|
||||||
|
*---------------------------*/
|
||||||
|
#include <stdlib.h> /* For things, like EXIT_*, NULL, ... */
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*---------------------------*
|
||||||
|
* commonly used defines: *
|
||||||
|
*---------------------------*/
|
||||||
|
#define THIS_EXEC_NAME "usb_hub"
|
||||||
|
#define HUB_MSG(...) do { \
|
||||||
|
printf(THIS_EXEC_NAME": "); \
|
||||||
|
printf(__VA_ARGS__); \
|
||||||
|
printf("; %s:%d\n", __func__, __LINE__); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/*---------------------------*
|
||||||
|
* debug helpers: *
|
||||||
|
*---------------------------*/
|
||||||
|
#ifdef HUB_DEBUG
|
||||||
|
#define HUB_DEBUG_MSG HUB_MSG
|
||||||
|
#define HUB_DEBUG_DUMP printf("%s():%d\n", __func__, __LINE__)
|
||||||
|
#else
|
||||||
|
#define HUB_DEBUG_MSG(...)
|
||||||
|
#define HUB_DEBUG_DUMP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !_COMMON_H_ */
|
111
minix/drivers/usb/usb_hub/urb_helper.c
Normal file
111
minix/drivers/usb/usb_hub/urb_helper.c
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* URB formatting related implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <minix/sysutil.h> /* panic */
|
||||||
|
#include <minix/usb.h> /* struct usb_ctrlrequest */
|
||||||
|
|
||||||
|
#include <string.h> /* memset */
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "urb_helper.h"
|
||||||
|
|
||||||
|
/*---------------------------*
|
||||||
|
* defined functions *
|
||||||
|
*---------------------------*/
|
||||||
|
/*===========================================================================*
|
||||||
|
* init_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
init_urb(struct ddekit_usb_urb * urb, struct ddekit_usb_dev * dev,
|
||||||
|
urb_ep_config * conf)
|
||||||
|
{
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Sanity checks */
|
||||||
|
assert(NULL != urb);
|
||||||
|
assert(NULL != dev);
|
||||||
|
assert((DDEKIT_USB_TRANSFER_BLK == conf->type) ||
|
||||||
|
(DDEKIT_USB_TRANSFER_CTL == conf->type) ||
|
||||||
|
(DDEKIT_USB_TRANSFER_INT == conf->type) ||
|
||||||
|
(DDEKIT_USB_TRANSFER_ISO == conf->type));
|
||||||
|
assert((conf->ep_num >= 0) && (conf->ep_num < 16));
|
||||||
|
assert((DDEKIT_USB_IN == conf->direction) ||
|
||||||
|
(DDEKIT_USB_OUT == conf->direction));
|
||||||
|
|
||||||
|
/* Clear block first */
|
||||||
|
memset(urb, 0, sizeof(*urb));
|
||||||
|
|
||||||
|
/* Set supplied values */
|
||||||
|
urb->dev = dev;
|
||||||
|
urb->type = conf->type;
|
||||||
|
urb->endpoint = conf->ep_num;
|
||||||
|
urb->direction = conf->direction;
|
||||||
|
urb->interval = conf->interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* attach_urb_data *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
attach_urb_data(struct ddekit_usb_urb * urb, int buf_type,
|
||||||
|
void * buf, ddekit_uint32_t buf_len)
|
||||||
|
{
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
assert(NULL != urb);
|
||||||
|
assert(NULL != buf);
|
||||||
|
|
||||||
|
/* Mutual exclusion */
|
||||||
|
if (URB_BUF_TYPE_DATA == buf_type) {
|
||||||
|
urb->data = buf;
|
||||||
|
urb->size = buf_len;
|
||||||
|
} else if ( URB_BUF_TYPE_SETUP == buf_type ) {
|
||||||
|
assert(sizeof(struct usb_ctrlrequest) == buf_len);
|
||||||
|
urb->setup_packet = buf;
|
||||||
|
} else
|
||||||
|
panic("Unexpected buffer type!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* blocking_urb_submit *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
blocking_urb_submit(struct ddekit_usb_urb * urb, ddekit_sem_t * sem,
|
||||||
|
int check_len)
|
||||||
|
{
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
assert(NULL != urb);
|
||||||
|
assert(NULL != sem);
|
||||||
|
assert((check_len == URB_SUBMIT_CHECK_LEN) ||
|
||||||
|
(check_len == URB_SUBMIT_ALLOW_MISMATCH));
|
||||||
|
|
||||||
|
/* Submit and block until semaphore gets up */
|
||||||
|
if (ddekit_usb_submit_urb(urb)) {
|
||||||
|
HUB_MSG("Submitting DDEKit URB failed");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
} else {
|
||||||
|
/* Submitting succeeded so block and wait for reply */
|
||||||
|
ddekit_sem_down(sem);
|
||||||
|
|
||||||
|
/* Check for DDEKit status first */
|
||||||
|
if (urb->status) {
|
||||||
|
HUB_MSG("Invalid DDEKit URB status");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
} else {
|
||||||
|
if (URB_SUBMIT_CHECK_LEN == check_len) {
|
||||||
|
/* Compare lengths */
|
||||||
|
if (urb->actual_length != urb->size) {
|
||||||
|
HUB_MSG("URB different than expected");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
47
minix/drivers/usb/usb_hub/urb_helper.h
Normal file
47
minix/drivers/usb/usb_hub/urb_helper.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* URB formatting related definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _URB_HELPER_H_
|
||||||
|
#define _URB_HELPER_H_
|
||||||
|
|
||||||
|
#include <ddekit/usb.h>
|
||||||
|
#include <ddekit/semaphore.h>
|
||||||
|
|
||||||
|
/* Possible values for attach_urb_data's buf_type */
|
||||||
|
/* Both may be used for single URB */
|
||||||
|
#define URB_BUF_TYPE_DATA 0 /* attached buffer is data buffer */
|
||||||
|
#define URB_BUF_TYPE_SETUP 1 /* attached buffer is setup structure */
|
||||||
|
|
||||||
|
/* Possible values for blocking_urb_submit's check_len */
|
||||||
|
/* Use URB_SUBMIT_CHECK_LEN when actual data buffer length returned
|
||||||
|
* by HCD must match expected length, supplied in attach_urb_data */
|
||||||
|
#define URB_SUBMIT_CHECK_LEN 0 /* return error on length mismatch */
|
||||||
|
#define URB_SUBMIT_ALLOW_MISMATCH 1 /* ignore length check */
|
||||||
|
|
||||||
|
/* Endpoint configuration related */
|
||||||
|
#define URB_INVALID_EP (-1) /* default for unset endpoint */
|
||||||
|
|
||||||
|
/*---------------------------*
|
||||||
|
* declared types *
|
||||||
|
*---------------------------*/
|
||||||
|
/* URB's endpoint configuration */
|
||||||
|
typedef struct urb_ep_config {
|
||||||
|
|
||||||
|
ddekit_int32_t ep_num;
|
||||||
|
ddekit_int32_t direction;
|
||||||
|
ddekit_int32_t type;
|
||||||
|
ddekit_int32_t max_packet_size;
|
||||||
|
ddekit_int32_t interval;
|
||||||
|
}
|
||||||
|
urb_ep_config;
|
||||||
|
|
||||||
|
/*---------------------------*
|
||||||
|
* declared functions *
|
||||||
|
*---------------------------*/
|
||||||
|
void init_urb(struct ddekit_usb_urb *, struct ddekit_usb_dev *,
|
||||||
|
urb_ep_config *);
|
||||||
|
void attach_urb_data(struct ddekit_usb_urb *, int, void *, ddekit_uint32_t);
|
||||||
|
int blocking_urb_submit(struct ddekit_usb_urb *, ddekit_sem_t *, int);
|
||||||
|
|
||||||
|
#endif /* !_URB_HELPER_H_ */
|
937
minix/drivers/usb/usb_hub/usb_hub.c
Normal file
937
minix/drivers/usb/usb_hub/usb_hub.c
Normal file
|
@ -0,0 +1,937 @@
|
||||||
|
/*
|
||||||
|
* Minix3 USB hub driver implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h> /* memset */
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h> /* nanosleep */
|
||||||
|
|
||||||
|
#include <ddekit/thread.h>
|
||||||
|
#include <minix/sef.h>
|
||||||
|
#include <minix/sysutil.h> /* panic */
|
||||||
|
#include <minix/usb.h> /* usb_ctrlrequest TODO: remove me */
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "urb_helper.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------*
|
||||||
|
* declared functions *
|
||||||
|
*---------------------------*/
|
||||||
|
/* TODO: these are missing from DDE header files */
|
||||||
|
extern void ddekit_minix_wait_exit(void);
|
||||||
|
extern void ddekit_shutdown(void);
|
||||||
|
|
||||||
|
/* SEF related functions */
|
||||||
|
static int hub_sef_hdlr(int, sef_init_info_t *);
|
||||||
|
static void hub_signal_handler(int);
|
||||||
|
|
||||||
|
/* DDEKit IPC related */
|
||||||
|
static void ddekit_usb_task(void *);
|
||||||
|
|
||||||
|
/* DDEKit's USB driver callbacks */
|
||||||
|
static void usb_driver_completion(void *);
|
||||||
|
static void usb_driver_connect(struct ddekit_usb_dev *, unsigned int);
|
||||||
|
static void usb_driver_disconnect(struct ddekit_usb_dev *);
|
||||||
|
|
||||||
|
/* Hub driver main task */
|
||||||
|
static void hub_task(void *);
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------*
|
||||||
|
* class specific stuff *
|
||||||
|
*---------------------------*/
|
||||||
|
#define HUB_PACKED __attribute__((__packed__))
|
||||||
|
|
||||||
|
/* How often to check for changes */
|
||||||
|
#define USB_HUB_POLLING_INTERVAL 1000
|
||||||
|
|
||||||
|
/* Max number of hub ports */
|
||||||
|
#define USB_HUB_PORT_LIMIT 8
|
||||||
|
|
||||||
|
/* Limits number of communication retries (when needed) */
|
||||||
|
#define USB_HUB_MAX_TRIES 3
|
||||||
|
|
||||||
|
/* How long to wait between retries, in case of reset error (in nanoseconds) */
|
||||||
|
#define USB_HUB_RESET_DELAY 200000000 /* 200ms */
|
||||||
|
|
||||||
|
/* Hub descriptor type */
|
||||||
|
#define USB_HUB_DESCRIPTOR_TYPE 0x29
|
||||||
|
|
||||||
|
/* Hub descriptor structure */
|
||||||
|
typedef struct HUB_PACKED hub_descriptor {
|
||||||
|
|
||||||
|
uint8_t bDescLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint8_t bNbrPorts;
|
||||||
|
uint16_t wHubCharacteristics;
|
||||||
|
uint8_t bPwrOn2PwrGood;
|
||||||
|
uint8_t bHubContrCurrent;
|
||||||
|
/* Remaining variable length fields are ignored for now */
|
||||||
|
}
|
||||||
|
hub_descriptor;
|
||||||
|
|
||||||
|
/* Hub port status structure, as defined in USB 2.0 document */
|
||||||
|
typedef struct HUB_PACKED hub_port_status {
|
||||||
|
|
||||||
|
uint32_t PORT_CONNECTION : 1;
|
||||||
|
uint32_t PORT_ENABLE : 1;
|
||||||
|
uint32_t PORT_SUSPEND : 1;
|
||||||
|
uint32_t PORT_OVER_CURRENT : 1;
|
||||||
|
uint32_t PORT_RESET : 1;
|
||||||
|
uint32_t RESERVED1 : 3;
|
||||||
|
|
||||||
|
uint32_t PORT_POWER : 1;
|
||||||
|
uint32_t PORT_LOW_SPEED : 1;
|
||||||
|
uint32_t PORT_HIGH_SPEED : 1;
|
||||||
|
uint32_t PORT_TEST : 1;
|
||||||
|
uint32_t PORT_INDICATOR : 1;
|
||||||
|
uint32_t RESERVED2 : 3;
|
||||||
|
|
||||||
|
uint32_t C_PORT_CONNECTION : 1;
|
||||||
|
uint32_t C_PORT_ENABLE : 1;
|
||||||
|
uint32_t C_PORT_SUSPEND : 1;
|
||||||
|
uint32_t C_PORT_OVER_CURRENT : 1;
|
||||||
|
uint32_t C_PORT_RESET : 1;
|
||||||
|
uint32_t RESERVED3 : 11;
|
||||||
|
}
|
||||||
|
hub_port_status;
|
||||||
|
|
||||||
|
/* Hub Class Feature Selectors */
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
C_HUB_LOCAL_POWER = 0 ,
|
||||||
|
C_HUB_OVER_CURRENT = 1 ,
|
||||||
|
PORT_CONNECTION = 0 ,
|
||||||
|
PORT_ENABLE = 1 ,
|
||||||
|
PORT_SUSPEND = 2 ,
|
||||||
|
PORT_OVER_CURRENT = 3 ,
|
||||||
|
PORT_RESET = 4 ,
|
||||||
|
PORT_POWER = 8 ,
|
||||||
|
PORT_LOW_SPEED = 9 ,
|
||||||
|
C_PORT_CONNECTION = 16,
|
||||||
|
C_PORT_ENABLE = 17,
|
||||||
|
C_PORT_SUSPEND = 18,
|
||||||
|
C_PORT_OVER_CURRENT = 19,
|
||||||
|
C_PORT_RESET = 20,
|
||||||
|
PORT_TEST = 21,
|
||||||
|
PORT_INDICATOR = 22
|
||||||
|
}
|
||||||
|
class_feature;
|
||||||
|
|
||||||
|
/* Hub Class Request Codes */
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
GET_STATUS = 0 ,
|
||||||
|
CLEAR_FEATURE = 1 ,
|
||||||
|
RESERVED1 = 2 ,
|
||||||
|
SET_FEATURE = 3 ,
|
||||||
|
RESERVED2 = 4 ,
|
||||||
|
RESERVED3 = 5 ,
|
||||||
|
GET_DESCRIPTOR = 6 ,
|
||||||
|
SET_DESCRIPTOR = 7 ,
|
||||||
|
CLEAR_TT_BUFFER = 8 ,
|
||||||
|
RESET_TT = 9 ,
|
||||||
|
GET_TT_STATE = 10,
|
||||||
|
STOP_TT = 11
|
||||||
|
}
|
||||||
|
class_code;
|
||||||
|
|
||||||
|
/* Hub port connection state */
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
HUB_PORT_DISCONN = 0,
|
||||||
|
HUB_PORT_CONN = 1,
|
||||||
|
HUB_PORT_ERROR = 2
|
||||||
|
}
|
||||||
|
port_conn;
|
||||||
|
|
||||||
|
/* Hub port connection changes */
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
HUB_CHANGE_NONE = 0, /* Nothing changed since last poll */
|
||||||
|
HUB_CHANGE_CONN = 1, /* Device was just connected */
|
||||||
|
HUB_CHANGE_DISCONN= 2, /* Device was just disconnected */
|
||||||
|
HUB_CHANGE_STATUS_ERR = 3, /* Port status mismatch */
|
||||||
|
HUB_CHANGE_COM_ERR = 4 /* Something wrong happened to driver */
|
||||||
|
}
|
||||||
|
port_change;
|
||||||
|
|
||||||
|
/* Hub get class specific descriptor call */
|
||||||
|
static int hub_get_descriptor(hub_descriptor *);
|
||||||
|
|
||||||
|
/* Hub Set/ClearPortFeature call */
|
||||||
|
static int hub_port_feature(int, class_code, class_feature);
|
||||||
|
|
||||||
|
/* Hub GetPortStatus call */
|
||||||
|
static int hub_get_port_status(int, hub_port_status *);
|
||||||
|
|
||||||
|
/* Handle port status change */
|
||||||
|
static port_change hub_handle_change(int, hub_port_status *);
|
||||||
|
|
||||||
|
/* Handle port connection */
|
||||||
|
static int hub_handle_connection(int, hub_port_status *);
|
||||||
|
|
||||||
|
/* Handle port disconnection */
|
||||||
|
static int hub_handle_disconnection(int);
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------*
|
||||||
|
* defined variables *
|
||||||
|
*---------------------------*/
|
||||||
|
/* USB hub driver state */
|
||||||
|
typedef struct hub_state {
|
||||||
|
|
||||||
|
hub_descriptor descriptor; /* Class specific descriptor */
|
||||||
|
struct ddekit_usb_dev * dev; /* DDEKit device */
|
||||||
|
int num_ports; /* Number of hub ports */
|
||||||
|
port_conn conn[USB_HUB_PORT_LIMIT]; /* Map of connected ports */
|
||||||
|
}
|
||||||
|
hub_state;
|
||||||
|
|
||||||
|
/* Current hub driver state */
|
||||||
|
static hub_state driver_state;
|
||||||
|
|
||||||
|
/* USB callback structure */
|
||||||
|
static struct ddekit_usb_driver usb_driver = {
|
||||||
|
.completion = usb_driver_completion,
|
||||||
|
.connect = usb_driver_connect,
|
||||||
|
.disconnect = usb_driver_disconnect
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Semaphore used to block hub thread to
|
||||||
|
* allow DDE dispatcher operation */
|
||||||
|
static ddekit_sem_t * hub_sem = NULL;
|
||||||
|
|
||||||
|
/* USB hub thread */
|
||||||
|
ddekit_thread_t * hub_thread = NULL;
|
||||||
|
|
||||||
|
/* DDEKit USB message handling thread */
|
||||||
|
ddekit_thread_t * ddekit_usb_thread = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------*
|
||||||
|
* defined functions *
|
||||||
|
*---------------------------*/
|
||||||
|
/*===========================================================================*
|
||||||
|
* main *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
main(int argc, char * argv[])
|
||||||
|
{
|
||||||
|
HUB_MSG("Starting driver... (built: %s %s)", __DATE__, __TIME__);
|
||||||
|
|
||||||
|
/* Store arguments for future parsing */
|
||||||
|
env_setargs(argc, argv);
|
||||||
|
|
||||||
|
/* Clear current state */
|
||||||
|
memset(&driver_state, 0, sizeof(driver_state));
|
||||||
|
|
||||||
|
/* Initialize SEF related callbacks */
|
||||||
|
sef_setcb_init_fresh(hub_sef_hdlr);
|
||||||
|
sef_setcb_init_lu(hub_sef_hdlr);
|
||||||
|
sef_setcb_init_restart(hub_sef_hdlr);
|
||||||
|
sef_setcb_signal_handler(hub_signal_handler);
|
||||||
|
|
||||||
|
/* Initialize DDEkit (involves sef_startup()) */
|
||||||
|
ddekit_init();
|
||||||
|
HUB_DEBUG_MSG("DDEkit ready...");
|
||||||
|
|
||||||
|
/* Semaphore initialization */
|
||||||
|
hub_sem = ddekit_sem_init(0);
|
||||||
|
if (NULL == hub_sem)
|
||||||
|
panic("Initializing USB hub semaphore, failed!");
|
||||||
|
|
||||||
|
/* Starting hub thread */
|
||||||
|
hub_thread = ddekit_thread_create(hub_task, NULL, "hub_task");
|
||||||
|
if (NULL == hub_thread)
|
||||||
|
panic("Initializing USB hub thread failed!");
|
||||||
|
|
||||||
|
HUB_DEBUG_MSG("USB HUB task ready...");
|
||||||
|
|
||||||
|
/* Run USB IPC task to collect messages */
|
||||||
|
ddekit_usb_thread = ddekit_thread_create(ddekit_usb_task, NULL,
|
||||||
|
"ddekit_task" );
|
||||||
|
if (NULL == ddekit_usb_thread)
|
||||||
|
panic("Initializing ddekit_usb_thread failed!");
|
||||||
|
|
||||||
|
HUB_DEBUG_MSG("USB IPC task ready...");
|
||||||
|
|
||||||
|
/* Block and wait until exit signal is received */
|
||||||
|
ddekit_minix_wait_exit();
|
||||||
|
HUB_DEBUG_MSG("Exiting...");
|
||||||
|
|
||||||
|
/* Release objects that were explicitly allocated above */
|
||||||
|
ddekit_thread_terminate(ddekit_usb_thread);
|
||||||
|
ddekit_thread_terminate(hub_thread);
|
||||||
|
ddekit_sem_deinit(hub_sem);
|
||||||
|
|
||||||
|
/* TODO: No ddekit_deinit for proper cleanup? */
|
||||||
|
|
||||||
|
HUB_DEBUG_MSG("Cleanup completed...");
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hub_sef_hdlr *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hub_sef_hdlr(int type, sef_init_info_t * UNUSED(info))
|
||||||
|
{
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case SEF_INIT_FRESH:
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
case SEF_INIT_LU:
|
||||||
|
case SEF_INIT_RESTART:
|
||||||
|
HUB_MSG("Only 'fresh' SEF initialization supported");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
HUB_MSG("Illegal SEF type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hub_signal_handler *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hub_signal_handler(int this_signal)
|
||||||
|
{
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
HUB_MSG("Handling signal 0x%X", this_signal);
|
||||||
|
|
||||||
|
/* TODO: Any signal means shutdown for now (it may be OK anyway) */
|
||||||
|
/* Try graceful DDEKit exit */
|
||||||
|
ddekit_shutdown();
|
||||||
|
|
||||||
|
/* Unreachable, when ddekit_shutdown works correctly */
|
||||||
|
panic("Calling ddekit_shutdown failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* ddekit_usb_task *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
ddekit_usb_task(void * UNUSED(arg))
|
||||||
|
{
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* TODO: This call was meant to return 'int' but loops forever instead,
|
||||||
|
* so no return value is checked */
|
||||||
|
ddekit_usb_init(&usb_driver, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usb_driver_completion *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
usb_driver_completion(void * UNUSED(priv))
|
||||||
|
{
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Last request was completed so allow continuing
|
||||||
|
* execution from place where semaphore was downed */
|
||||||
|
ddekit_sem_up(hub_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usb_driver_connect *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
usb_driver_connect(struct ddekit_usb_dev * dev, unsigned int interfaces)
|
||||||
|
{
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
if (NULL != driver_state.dev)
|
||||||
|
panic("HUB device driver can be connected only once!");
|
||||||
|
|
||||||
|
/* Clear current state */
|
||||||
|
memset(&driver_state, 0, sizeof(driver_state));
|
||||||
|
|
||||||
|
/* Hold host information for future use */
|
||||||
|
driver_state.dev = dev;
|
||||||
|
|
||||||
|
/* Let driver logic work */
|
||||||
|
ddekit_sem_up(hub_sem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usb_driver_disconnect *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
usb_driver_disconnect(struct ddekit_usb_dev * UNUSED(dev))
|
||||||
|
{
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
if (NULL == driver_state.dev)
|
||||||
|
panic("HUB device driver was never connected!");
|
||||||
|
|
||||||
|
/* Discard connected device information */
|
||||||
|
driver_state.dev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hub_task *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hub_task(void * UNUSED(arg))
|
||||||
|
{
|
||||||
|
hub_port_status port_status;
|
||||||
|
hub_state * s;
|
||||||
|
hub_descriptor * d;
|
||||||
|
int port;
|
||||||
|
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* For short */
|
||||||
|
s = &(driver_state);
|
||||||
|
d = &(s->descriptor);
|
||||||
|
|
||||||
|
/* Wait for connection */
|
||||||
|
ddekit_sem_down(hub_sem);
|
||||||
|
|
||||||
|
if (hub_get_descriptor(d)) {
|
||||||
|
HUB_MSG("Getting hub descriptor failed");
|
||||||
|
goto HUB_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output hub descriptor in debug mode */
|
||||||
|
HUB_DEBUG_MSG("bDescLength %4X", d->bDescLength);
|
||||||
|
HUB_DEBUG_MSG("bDescriptorType %4X", d->bDescriptorType);
|
||||||
|
HUB_DEBUG_MSG("bNbrPorts %4X", d->bNbrPorts);
|
||||||
|
HUB_DEBUG_MSG("wHubCharacteristics %4X", d->wHubCharacteristics);
|
||||||
|
HUB_DEBUG_MSG("bPwrOn2PwrGood %4X", d->bPwrOn2PwrGood);
|
||||||
|
HUB_DEBUG_MSG("bHubContrCurrent %4X", d->bHubContrCurrent);
|
||||||
|
|
||||||
|
/* Check for sane number of ports... */
|
||||||
|
if (d->bNbrPorts > USB_HUB_PORT_LIMIT) {
|
||||||
|
HUB_MSG("Too many hub ports declared: %d", d->bNbrPorts);
|
||||||
|
goto HUB_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ...and reassign */
|
||||||
|
s->num_ports = (int)d->bNbrPorts;
|
||||||
|
|
||||||
|
/* Initialize all available ports starting
|
||||||
|
* from 1, as defined by USB 2.0 document */
|
||||||
|
for (port = 1; port <= s->num_ports; port++) {
|
||||||
|
if (hub_port_feature(port, SET_FEATURE, PORT_POWER)) {
|
||||||
|
HUB_MSG("Powering port%d failed", port);
|
||||||
|
goto HUB_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connection polling loop
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
for (port = 1; port <= s->num_ports; port++) {
|
||||||
|
|
||||||
|
/* Ignore previously blocked ports */
|
||||||
|
if (HUB_PORT_ERROR == s->conn[port]) {
|
||||||
|
HUB_DEBUG_MSG("Blocked hub port ignored");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get port status */
|
||||||
|
if (hub_get_port_status(port, &port_status)) {
|
||||||
|
HUB_MSG("Reading port%d status failed", port);
|
||||||
|
goto HUB_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resolve port changes */
|
||||||
|
switch (hub_handle_change(port, &port_status)) {
|
||||||
|
|
||||||
|
case HUB_CHANGE_NONE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HUB_CHANGE_CONN:
|
||||||
|
s->conn[port] = HUB_PORT_CONN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HUB_CHANGE_DISCONN:
|
||||||
|
s->conn[port] = HUB_PORT_DISCONN;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HUB_CHANGE_STATUS_ERR:
|
||||||
|
/* Turn off port */
|
||||||
|
if (hub_port_feature(port,
|
||||||
|
CLEAR_FEATURE,
|
||||||
|
PORT_POWER)) {
|
||||||
|
HUB_MSG("Halting port%d "
|
||||||
|
"failed", port);
|
||||||
|
goto HUB_ERROR;
|
||||||
|
}
|
||||||
|
/* Block this port forever */
|
||||||
|
s->conn[port] = HUB_PORT_ERROR;
|
||||||
|
|
||||||
|
HUB_MSG("Port%d status ERROR", port);
|
||||||
|
HUB_MSG("Port%d will be blocked, until "
|
||||||
|
"hub is detached", port);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HUB_CHANGE_COM_ERR:
|
||||||
|
/* Serious error, hang */
|
||||||
|
HUB_MSG("Handling port%d "
|
||||||
|
"change failed", port);
|
||||||
|
goto HUB_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ddekit_thread_msleep(USB_HUB_POLLING_INTERVAL);
|
||||||
|
HUB_DEBUG_MSG("Polling USB hub for status change");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
HUB_ERROR:
|
||||||
|
for (;;) {
|
||||||
|
/* Hang till removed by devmand */
|
||||||
|
HUB_MSG("Hub driver error occurred, hanging up");
|
||||||
|
ddekit_sem_down(hub_sem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hub_get_descriptor *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hub_get_descriptor(hub_descriptor * descriptor)
|
||||||
|
{
|
||||||
|
/* URB to be send */
|
||||||
|
struct ddekit_usb_urb urb;
|
||||||
|
|
||||||
|
/* Setup buffer to be attached */
|
||||||
|
struct usb_ctrlrequest setup_buf;
|
||||||
|
|
||||||
|
/* Control EP configuration */
|
||||||
|
urb_ep_config ep_conf;
|
||||||
|
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Initialize EP configuration */
|
||||||
|
ep_conf.ep_num = 0;
|
||||||
|
ep_conf.direction = DDEKIT_USB_IN;
|
||||||
|
ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
|
||||||
|
ep_conf.max_packet_size = 0;
|
||||||
|
ep_conf.interval = 0;
|
||||||
|
|
||||||
|
/* Reset URB and assign given values */
|
||||||
|
init_urb(&urb, driver_state.dev, &ep_conf);
|
||||||
|
|
||||||
|
/* Clear setup data */
|
||||||
|
memset(&setup_buf, 0, sizeof(setup_buf));
|
||||||
|
|
||||||
|
/* Class get hub descriptor request */
|
||||||
|
setup_buf.bRequestType = 0xA0;
|
||||||
|
setup_buf.bRequest = 0x06;
|
||||||
|
setup_buf.wValue = USB_HUB_DESCRIPTOR_TYPE << 8;
|
||||||
|
setup_buf.wIndex = 0x00;
|
||||||
|
setup_buf.wLength = sizeof(*descriptor);
|
||||||
|
|
||||||
|
/* Attach buffers to URB */
|
||||||
|
attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
|
||||||
|
&setup_buf, sizeof(setup_buf));
|
||||||
|
attach_urb_data(&urb, URB_BUF_TYPE_DATA,
|
||||||
|
descriptor, sizeof(*descriptor));
|
||||||
|
|
||||||
|
/* Send and wait for response */
|
||||||
|
if (blocking_urb_submit(&urb, hub_sem, URB_SUBMIT_CHECK_LEN)) {
|
||||||
|
HUB_MSG("Submitting HUB URB failed");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
} else {
|
||||||
|
HUB_DEBUG_MSG("HUB descriptor received");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hub_port_feature *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hub_port_feature(int port_num, class_code code, class_feature feature)
|
||||||
|
{
|
||||||
|
/* URB to be send */
|
||||||
|
struct ddekit_usb_urb urb;
|
||||||
|
|
||||||
|
/* Setup buffer to be attached */
|
||||||
|
struct usb_ctrlrequest setup_buf;
|
||||||
|
|
||||||
|
/* Control EP configuration */
|
||||||
|
urb_ep_config ep_conf;
|
||||||
|
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* TODO: Add more checks when needed */
|
||||||
|
if (!((port_num <= driver_state.num_ports) && (port_num > 0)))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (!((code == SET_FEATURE) || (code == CLEAR_FEATURE)))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (!((feature == PORT_RESET) || (feature == PORT_POWER) ||
|
||||||
|
(feature == C_PORT_CONNECTION) || (feature == C_PORT_RESET)))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
/* Initialize EP configuration */
|
||||||
|
ep_conf.ep_num = 0;
|
||||||
|
ep_conf.direction = DDEKIT_USB_OUT;
|
||||||
|
ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
|
||||||
|
ep_conf.max_packet_size = 0;
|
||||||
|
ep_conf.interval = 0;
|
||||||
|
|
||||||
|
/* Reset URB and assign given values */
|
||||||
|
init_urb(&urb, driver_state.dev, &ep_conf);
|
||||||
|
|
||||||
|
/* Clear setup data */
|
||||||
|
memset(&setup_buf, 0, sizeof(setup_buf));
|
||||||
|
|
||||||
|
/* Standard get endpoint request */
|
||||||
|
setup_buf.bRequestType = 0x23;
|
||||||
|
setup_buf.bRequest = (u8_t)code;
|
||||||
|
setup_buf.wValue = (u16_t)feature;
|
||||||
|
setup_buf.wIndex = (u16_t)port_num;
|
||||||
|
setup_buf.wLength = 0;
|
||||||
|
|
||||||
|
/* Attach buffers to URB */
|
||||||
|
attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
|
||||||
|
&setup_buf, sizeof(setup_buf));
|
||||||
|
|
||||||
|
/* Send and wait for response */
|
||||||
|
if (blocking_urb_submit(&urb, hub_sem, URB_SUBMIT_CHECK_LEN)) {
|
||||||
|
HUB_MSG("Submitting HUB URB failed");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
} else {
|
||||||
|
HUB_DEBUG_MSG("PortFeature operation completed");
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hub_get_port_status *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hub_get_port_status(int port_num, hub_port_status * p)
|
||||||
|
{
|
||||||
|
/* URB to be send */
|
||||||
|
struct ddekit_usb_urb urb;
|
||||||
|
|
||||||
|
/* Setup buffer to be attached */
|
||||||
|
struct usb_ctrlrequest setup_buf;
|
||||||
|
|
||||||
|
/* Control EP configuration */
|
||||||
|
urb_ep_config ep_conf;
|
||||||
|
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
if (!((port_num <= driver_state.num_ports) && (port_num > 0)))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
/* Initialize EP configuration */
|
||||||
|
ep_conf.ep_num = 0;
|
||||||
|
ep_conf.direction = DDEKIT_USB_IN;
|
||||||
|
ep_conf.type = DDEKIT_USB_TRANSFER_CTL;
|
||||||
|
ep_conf.max_packet_size = 0;
|
||||||
|
ep_conf.interval = 0;
|
||||||
|
|
||||||
|
/* Reset URB and assign given values */
|
||||||
|
init_urb(&urb, driver_state.dev, &ep_conf);
|
||||||
|
|
||||||
|
/* Clear setup data */
|
||||||
|
memset(&setup_buf, 0, sizeof(setup_buf));
|
||||||
|
|
||||||
|
/* Standard get endpoint request */
|
||||||
|
setup_buf.bRequestType = 0xA3;
|
||||||
|
setup_buf.bRequest = (u8_t)GET_STATUS;
|
||||||
|
setup_buf.wValue = 0x00;
|
||||||
|
setup_buf.wIndex = (u16_t)port_num;
|
||||||
|
setup_buf.wLength = sizeof(*p);
|
||||||
|
|
||||||
|
/* Attach buffers to URB */
|
||||||
|
attach_urb_data(&urb, URB_BUF_TYPE_SETUP,
|
||||||
|
&setup_buf, sizeof(setup_buf));
|
||||||
|
attach_urb_data(&urb, URB_BUF_TYPE_DATA,
|
||||||
|
p, sizeof(*p));
|
||||||
|
|
||||||
|
/* Send and wait for response */
|
||||||
|
if (blocking_urb_submit(&urb, hub_sem, URB_SUBMIT_CHECK_LEN)) {
|
||||||
|
HUB_MSG("Submitting HUB URB failed");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
} else {
|
||||||
|
HUB_DEBUG_MSG("Port%d status: ", port_num);
|
||||||
|
HUB_DEBUG_MSG("PORT_CONNECTION %01X", p->PORT_CONNECTION);
|
||||||
|
HUB_DEBUG_MSG("PORT_ENABLE %01X", p->PORT_ENABLE);
|
||||||
|
HUB_DEBUG_MSG("PORT_POWER %01X", p->PORT_POWER);
|
||||||
|
HUB_DEBUG_MSG("C_PORT_CONNECTION %01X", p->C_PORT_CONNECTION);
|
||||||
|
HUB_DEBUG_MSG("C_PORT_ENABLE %01X", p->C_PORT_ENABLE);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hub_handle_change *
|
||||||
|
*===========================================================================*/
|
||||||
|
static port_change
|
||||||
|
hub_handle_change(int port_num, hub_port_status * status)
|
||||||
|
{
|
||||||
|
port_conn * c;
|
||||||
|
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Possible combinations: */
|
||||||
|
/* Change = status->C_PORT_CONNECTION (hub connection change bit)
|
||||||
|
* Local = driver_state.conn[port_num] (local connection status)
|
||||||
|
* Remote = status->PORT_CONNECTION (hub connection status) */
|
||||||
|
/*
|
||||||
|
Case Change Local Remote Description
|
||||||
|
1. 1 1 1 Polling mismatch (quick disconn-conn)
|
||||||
|
2. 1 1 0 Just disconnected
|
||||||
|
3. 1 0 1 Just connected
|
||||||
|
4. 1 0 0 Polling mismatch (quick conn-disconn)
|
||||||
|
5. 0 1 1 Still connected
|
||||||
|
6. 0 1 0 Serious ERROR
|
||||||
|
7. 0 0 1 Serious ERROR
|
||||||
|
8. 0 0 0 Still disconnected
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Reassign for code cleanliness */
|
||||||
|
c = driver_state.conn;
|
||||||
|
|
||||||
|
/* Resolve combination */
|
||||||
|
if (status->C_PORT_CONNECTION) {
|
||||||
|
|
||||||
|
/* C_PORT_CONNECTION was set, so clear change bit
|
||||||
|
* to allow further polling */
|
||||||
|
if (hub_port_feature(port_num, CLEAR_FEATURE,
|
||||||
|
C_PORT_CONNECTION)) {
|
||||||
|
HUB_MSG("Clearing port%d change bit failed", port_num);
|
||||||
|
return HUB_CHANGE_COM_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HUB_PORT_CONN == c[port_num]) {
|
||||||
|
if (status->PORT_CONNECTION) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1
|
||||||
|
*/
|
||||||
|
/* Make hub disconnect and connect again */
|
||||||
|
if (hub_handle_disconnection(port_num) ||
|
||||||
|
hub_handle_connection(port_num, status))
|
||||||
|
return HUB_CHANGE_STATUS_ERR;
|
||||||
|
else
|
||||||
|
return HUB_CHANGE_CONN;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 2
|
||||||
|
*/
|
||||||
|
/* Handle disconnection */
|
||||||
|
if (hub_handle_disconnection(port_num))
|
||||||
|
return HUB_CHANGE_STATUS_ERR;
|
||||||
|
else
|
||||||
|
return HUB_CHANGE_DISCONN;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (HUB_PORT_DISCONN == c[port_num]) {
|
||||||
|
if (status->PORT_CONNECTION) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 3
|
||||||
|
*/
|
||||||
|
/* Handle connection */
|
||||||
|
if (hub_handle_connection(port_num, status))
|
||||||
|
return HUB_CHANGE_STATUS_ERR;
|
||||||
|
else
|
||||||
|
return HUB_CHANGE_CONN;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 4
|
||||||
|
*/
|
||||||
|
/* Since we were disconnected before and
|
||||||
|
* are disconnected now, additional handling
|
||||||
|
* may be ignored */
|
||||||
|
return HUB_CHANGE_NONE;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (HUB_PORT_CONN == c[port_num]) {
|
||||||
|
if (status->PORT_CONNECTION) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 5
|
||||||
|
*/
|
||||||
|
/* Connected (nothing changed) */
|
||||||
|
return HUB_CHANGE_NONE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 6
|
||||||
|
*/
|
||||||
|
/* Serious status error */
|
||||||
|
return HUB_CHANGE_STATUS_ERR;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (HUB_PORT_DISCONN == c[port_num]) {
|
||||||
|
if (status->PORT_CONNECTION) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 7
|
||||||
|
*/
|
||||||
|
/* Serious status error */
|
||||||
|
return HUB_CHANGE_STATUS_ERR;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 8
|
||||||
|
*/
|
||||||
|
/* Disconnected (nothing changed) */
|
||||||
|
return HUB_CHANGE_NONE;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return HUB_CHANGE_COM_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hub_handle_connection *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hub_handle_connection(int port_num, hub_port_status * status)
|
||||||
|
{
|
||||||
|
struct timespec wait_time;
|
||||||
|
int reset_tries;
|
||||||
|
long port_speed;
|
||||||
|
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
HUB_MSG("Device connected to port%d", port_num);
|
||||||
|
|
||||||
|
/* This should never happen if power-off works as intended */
|
||||||
|
if (status->C_PORT_RESET) {
|
||||||
|
HUB_MSG("Unexpected reset state for port%d", port_num);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start reset signaling for this port */
|
||||||
|
if (hub_port_feature(port_num, SET_FEATURE, PORT_RESET)) {
|
||||||
|
HUB_MSG("Resetting port%d failed", port_num);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_tries = 0;
|
||||||
|
wait_time.tv_sec = 0;
|
||||||
|
wait_time.tv_nsec = USB_HUB_RESET_DELAY;
|
||||||
|
|
||||||
|
/* Wait for reset completion */
|
||||||
|
while (!status->C_PORT_RESET) {
|
||||||
|
/* To avoid endless loop */
|
||||||
|
if (reset_tries >= USB_HUB_MAX_TRIES) {
|
||||||
|
HUB_MSG("Port%d reset took too long", port_num);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get port status again */
|
||||||
|
if (hub_get_port_status(port_num, status)) {
|
||||||
|
HUB_MSG("Reading port%d status failed", port_num);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_tries++;
|
||||||
|
|
||||||
|
/* Ignore potential signal interruption (no return value check),
|
||||||
|
* since it causes driver termination anyway */
|
||||||
|
if (nanosleep(&wait_time, NULL))
|
||||||
|
HUB_MSG("Calling nanosleep() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset completed */
|
||||||
|
HUB_DEBUG_MSG("Port%d reset complete", port_num);
|
||||||
|
|
||||||
|
/* Dump full status for analysis (high-speed, ...) */
|
||||||
|
HUB_DEBUG_MSG("C_PORT_CONNECTION %1X", status->C_PORT_CONNECTION );
|
||||||
|
HUB_DEBUG_MSG("C_PORT_ENABLE %1X", status->C_PORT_ENABLE );
|
||||||
|
HUB_DEBUG_MSG("C_PORT_OVER_CURRENT %1X", status->C_PORT_OVER_CURRENT);
|
||||||
|
HUB_DEBUG_MSG("C_PORT_RESET %1X", status->C_PORT_RESET );
|
||||||
|
HUB_DEBUG_MSG("C_PORT_SUSPEND %1X", status->C_PORT_SUSPEND );
|
||||||
|
HUB_DEBUG_MSG("PORT_CONNECTION %1X", status->PORT_CONNECTION );
|
||||||
|
HUB_DEBUG_MSG("PORT_ENABLE %1X", status->PORT_ENABLE );
|
||||||
|
HUB_DEBUG_MSG("PORT_HIGH_SPEED %1X", status->PORT_HIGH_SPEED );
|
||||||
|
HUB_DEBUG_MSG("PORT_INDICATOR %1X", status->PORT_INDICATOR );
|
||||||
|
HUB_DEBUG_MSG("PORT_LOW_SPEED %1X", status->PORT_LOW_SPEED );
|
||||||
|
HUB_DEBUG_MSG("PORT_OVER_CURRENT %1X", status->PORT_OVER_CURRENT );
|
||||||
|
HUB_DEBUG_MSG("PORT_POWER %1X", status->PORT_POWER );
|
||||||
|
HUB_DEBUG_MSG("PORT_RESET %1X", status->PORT_RESET );
|
||||||
|
HUB_DEBUG_MSG("PORT_SUSPEND %1X", status->PORT_SUSPEND );
|
||||||
|
HUB_DEBUG_MSG("PORT_TEST %1X", status->PORT_TEST );
|
||||||
|
|
||||||
|
/* Clear reset change bit for further devices */
|
||||||
|
if (hub_port_feature(port_num, CLEAR_FEATURE, C_PORT_RESET)) {
|
||||||
|
HUB_MSG("Clearing port%d reset bit failed", port_num);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should never happen */
|
||||||
|
if (!status->PORT_CONNECTION || !status->PORT_ENABLE) {
|
||||||
|
HUB_MSG("Port%d unexpectedly unavailable", port_num);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine port speed from status bits */
|
||||||
|
if (status->PORT_LOW_SPEED) {
|
||||||
|
if (status->PORT_HIGH_SPEED) {
|
||||||
|
HUB_MSG("Port%d has invalid speed flags", port_num);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
} else
|
||||||
|
port_speed = (long)DDEKIT_HUB_PORT_LS_CONN;
|
||||||
|
} else {
|
||||||
|
if (status->PORT_HIGH_SPEED)
|
||||||
|
port_speed = (long)DDEKIT_HUB_PORT_HS_CONN;
|
||||||
|
else
|
||||||
|
port_speed = (long)DDEKIT_HUB_PORT_FS_CONN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Signal to HCD that port has device connected at given speed */
|
||||||
|
return ddekit_usb_info(driver_state.dev, port_speed, (long)port_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hub_handle_disconnection *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hub_handle_disconnection(int port_num)
|
||||||
|
{
|
||||||
|
HUB_DEBUG_DUMP;
|
||||||
|
|
||||||
|
HUB_MSG("Device disconnected from port%d", port_num);
|
||||||
|
|
||||||
|
return ddekit_usb_info(driver_state.dev, (long)DDEKIT_HUB_PORT_DISCONN,
|
||||||
|
(long)port_num);
|
||||||
|
}
|
15
minix/drivers/usb/usb_hub/usb_hub.conf
Normal file
15
minix/drivers/usb/usb_hub/usb_hub.conf
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
service usb_hub
|
||||||
|
{
|
||||||
|
system
|
||||||
|
PRIVCTL # 4
|
||||||
|
UMAP # 14
|
||||||
|
IRQCTL # 19
|
||||||
|
DEVIO # 21
|
||||||
|
SDEVIO # 22
|
||||||
|
;
|
||||||
|
ipc
|
||||||
|
SYSTEM pm rs log tty ds vfs vm amddev devman
|
||||||
|
pci usbd
|
||||||
|
;
|
||||||
|
uid 0;
|
||||||
|
};
|
|
@ -20,6 +20,7 @@ static int create_read_capacity_scsi_cmd(mass_storage_cbw *);
|
||||||
static int create_write_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
|
static int create_write_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
|
||||||
static int create_read_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
|
static int create_read_scsi_cmd(mass_storage_cbw *, scsi_transfer *);
|
||||||
static int create_mode_sense_scsi_cmd(mass_storage_cbw *);
|
static int create_mode_sense_scsi_cmd(mass_storage_cbw *);
|
||||||
|
static int create_request_sense_scsi_cmd(mass_storage_cbw *);
|
||||||
|
|
||||||
/*---------------------------*
|
/*---------------------------*
|
||||||
* defined functions *
|
* defined functions *
|
||||||
|
@ -47,6 +48,8 @@ create_scsi_cmd(mass_storage_cbw * cbw, int cmd, scsi_transfer * info)
|
||||||
return create_read_scsi_cmd(cbw, info);
|
return create_read_scsi_cmd(cbw, info);
|
||||||
case SCSI_MODE_SENSE:
|
case SCSI_MODE_SENSE:
|
||||||
return create_mode_sense_scsi_cmd(cbw);
|
return create_mode_sense_scsi_cmd(cbw);
|
||||||
|
case SCSI_REQUEST_SENSE:
|
||||||
|
return create_request_sense_scsi_cmd(cbw);
|
||||||
default:
|
default:
|
||||||
MASS_MSG("Invalid SCSI command!");
|
MASS_MSG("Invalid SCSI command!");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -175,6 +178,25 @@ create_mode_sense_scsi_cmd(mass_storage_cbw * cbw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* create_request_sense_scsi_cmd *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
create_request_sense_scsi_cmd(mass_storage_cbw * cbw)
|
||||||
|
{
|
||||||
|
MASS_DEBUG_DUMP;
|
||||||
|
|
||||||
|
cbw->dCBWDataTransferLength = SCSI_REQUEST_SENSE_DATA_LEN;
|
||||||
|
cbw->bCBWFlags = CBW_FLAGS_IN;
|
||||||
|
cbw->bCDBLength = SCSI_REQUEST_SENSE_CMD_LEN;
|
||||||
|
|
||||||
|
SCSI_SET_REQUEST_SENSE_OP_CODE(cbw->CBWCB);
|
||||||
|
SCSI_SET_REQUEST_SENSE_ALLOC(cbw->CBWCB, SCSI_REQUEST_SENSE_DATA_LEN);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* check_inquiry_reply *
|
* check_inquiry_reply *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
|
|
@ -27,25 +27,13 @@
|
||||||
|
|
||||||
#include "bulk.h"
|
#include "bulk.h"
|
||||||
|
|
||||||
#define SCSI_FORMAT_UNIT (0x04)
|
|
||||||
#define SCSI_INQUIRY (0x12)
|
#define SCSI_INQUIRY (0x12)
|
||||||
#define SCSI_START_STOP (0x1B)
|
|
||||||
#define SCSI_MODE_SELECT (0x55)
|
|
||||||
#define SCSI_MODE_SENSE (0x5A)
|
#define SCSI_MODE_SENSE (0x5A)
|
||||||
#define SCSI_PREVENT_ALLOW (0x1E)
|
|
||||||
#define SCSI_READ (0x28)
|
#define SCSI_READ (0x28)
|
||||||
#define SCSI_READ_12 (0xA8)
|
|
||||||
#define SCSI_READ_CAPACITY (0x25)
|
#define SCSI_READ_CAPACITY (0x25)
|
||||||
#define SCSI_READ_FORMAT_CAP (0x23)
|
|
||||||
#define SCSI_REQUEST_SENSE (0x03)
|
#define SCSI_REQUEST_SENSE (0x03)
|
||||||
#define SCSI_REZERO_UNIT (0x01)
|
|
||||||
#define SCSI_SEEK (0x2B)
|
|
||||||
#define SCSI_SEND_DIAGNOSTIC (0x1D)
|
|
||||||
#define SCSI_TEST_UNIT_READY (0x00)
|
#define SCSI_TEST_UNIT_READY (0x00)
|
||||||
#define SCSI_VERIFY (0x2F)
|
|
||||||
#define SCSI_WRITE (0x2A)
|
#define SCSI_WRITE (0x2A)
|
||||||
#define SCSI_WRITE_12 (0xAA)
|
|
||||||
#define SCSI_WRITE_VERIFY (0x2E)
|
|
||||||
|
|
||||||
#define SCSI_INQUIRY_DATA_LEN (36)
|
#define SCSI_INQUIRY_DATA_LEN (36)
|
||||||
#define SCSI_INQUIRY_CMD_LEN (6)
|
#define SCSI_INQUIRY_CMD_LEN (6)
|
||||||
|
@ -59,6 +47,9 @@
|
||||||
#define SCSI_READ_CAPACITY_DATA_LEN (8)
|
#define SCSI_READ_CAPACITY_DATA_LEN (8)
|
||||||
#define SCSI_READ_CAPACITY_CMD_LEN (10)
|
#define SCSI_READ_CAPACITY_CMD_LEN (10)
|
||||||
|
|
||||||
|
#define SCSI_REQUEST_SENSE_DATA_LEN (18)
|
||||||
|
#define SCSI_REQUEST_SENSE_CMD_LEN (6)
|
||||||
|
|
||||||
#define SCSI_TEST_DATA_LEN (0)
|
#define SCSI_TEST_DATA_LEN (0)
|
||||||
#define SCSI_TEST_CMD_LEN (6)
|
#define SCSI_TEST_CMD_LEN (6)
|
||||||
|
|
||||||
|
@ -117,6 +108,10 @@
|
||||||
#define SCSI_GET_READ_CAPACITY_LBA(x) SCSI_RD4((x), 0)
|
#define SCSI_GET_READ_CAPACITY_LBA(x) SCSI_RD4((x), 0)
|
||||||
#define SCSI_GET_READ_CAPACITY_BLEN(x) SCSI_RD4((x), 4)
|
#define SCSI_GET_READ_CAPACITY_BLEN(x) SCSI_RD4((x), 4)
|
||||||
|
|
||||||
|
#define SCSI_SET_REQUEST_SENSE_OP_CODE(x) SCSI_WR1((x), 0, \
|
||||||
|
SCSI_REQUEST_SENSE)
|
||||||
|
#define SCSI_SET_REQUEST_SENSE_ALLOC(x, alloc) SCSI_WR1((x), 4, (alloc))
|
||||||
|
|
||||||
#define SCSI_SET_TEST_OP_CODE(x) SCSI_WR1((x), 0, \
|
#define SCSI_SET_TEST_OP_CODE(x) SCSI_WR1((x), 0, \
|
||||||
SCSI_TEST_UNIT_READY)
|
SCSI_TEST_UNIT_READY)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* using DDEkit, and libblockdriver
|
* using DDEkit, and libblockdriver
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/cdefs.h> /* __CTASSERT() */
|
||||||
#include <sys/ioc_disk.h> /* cases for mass_storage_ioctl */
|
#include <sys/ioc_disk.h> /* cases for mass_storage_ioctl */
|
||||||
#ifdef USB_STORAGE_SIGNAL
|
#ifdef USB_STORAGE_SIGNAL
|
||||||
#include <sys/signal.h> /* signal handling */
|
#include <sys/signal.h> /* signal handling */
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <limits.h> /* ULONG_MAX */
|
#include <limits.h> /* ULONG_MAX */
|
||||||
|
#include <time.h> /* nanosleep */
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "bulk.h"
|
#include "bulk.h"
|
||||||
|
@ -62,6 +64,7 @@ static void ddekit_usb_task(void *);
|
||||||
/* Mass storage related prototypes */
|
/* Mass storage related prototypes */
|
||||||
static void mass_storage_task(void *);
|
static void mass_storage_task(void *);
|
||||||
static int mass_storage_test(void);
|
static int mass_storage_test(void);
|
||||||
|
static int mass_storage_check_error(void);
|
||||||
static int mass_storage_try_first_open(void);
|
static int mass_storage_try_first_open(void);
|
||||||
static int mass_storage_transfer_restrictions(u64_t, unsigned long);
|
static int mass_storage_transfer_restrictions(u64_t, unsigned long);
|
||||||
static ssize_t mass_storage_write(unsigned long, endpoint_t, iovec_t *,
|
static ssize_t mass_storage_write(unsigned long, endpoint_t, iovec_t *,
|
||||||
|
@ -96,6 +99,8 @@ static int mass_storage_parse_descriptors(char *, unsigned int, urb_ep_config *,
|
||||||
/*---------------------------*
|
/*---------------------------*
|
||||||
* defined variables *
|
* defined variables *
|
||||||
*---------------------------*/
|
*---------------------------*/
|
||||||
|
#define MASS_PACKED __attribute__((__packed__))
|
||||||
|
|
||||||
/* Mass Storage callback structure */
|
/* Mass Storage callback structure */
|
||||||
static struct blockdriver mass_storage = {
|
static struct blockdriver mass_storage = {
|
||||||
.bdr_type = BLOCKDRIVER_TYPE_DISK,
|
.bdr_type = BLOCKDRIVER_TYPE_DISK,
|
||||||
|
@ -149,6 +154,10 @@ static unsigned char buffer[BUFFER_SIZE];
|
||||||
/* Maximum 'Test Unit Ready' command retries */
|
/* Maximum 'Test Unit Ready' command retries */
|
||||||
#define MAX_TEST_RETRIES 3
|
#define MAX_TEST_RETRIES 3
|
||||||
|
|
||||||
|
/* 'Test Unit Ready' failure delay time (in nanoseconds) */
|
||||||
|
#define NEXT_TEST_DELAY 50000000 /* 50ms */
|
||||||
|
|
||||||
|
|
||||||
/*---------------------------*
|
/*---------------------------*
|
||||||
* defined functions *
|
* defined functions *
|
||||||
*---------------------------*/
|
*---------------------------*/
|
||||||
|
@ -589,23 +598,121 @@ static int
|
||||||
mass_storage_test(void)
|
mass_storage_test(void)
|
||||||
{
|
{
|
||||||
int repeat;
|
int repeat;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
struct timespec test_wait;
|
||||||
|
|
||||||
MASS_DEBUG_DUMP;
|
MASS_DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Delay between consecutive test commands, in case of their failure */
|
||||||
|
test_wait.tv_nsec = NEXT_TEST_DELAY;
|
||||||
|
test_wait.tv_sec = 0;
|
||||||
|
|
||||||
for (repeat = 0; repeat < MAX_TEST_RETRIES; repeat++) {
|
for (repeat = 0; repeat < MAX_TEST_RETRIES; repeat++) {
|
||||||
|
|
||||||
/* SCSI TEST UNIT READY OUT stage */
|
/* SCSI TEST UNIT READY OUT stage */
|
||||||
if (mass_storage_send_scsi_cbw_out(SCSI_TEST_UNIT_READY, NULL))
|
if (mass_storage_send_scsi_cbw_out(SCSI_TEST_UNIT_READY, NULL))
|
||||||
return EXIT_FAILURE;
|
return EIO;
|
||||||
|
|
||||||
/* TODO: Only CSW failure should normally contribute to retry */
|
/* TODO: Only CSW failure should normally contribute to retry */
|
||||||
|
|
||||||
/* SCSI TEST UNIT READY IN stage */
|
/* SCSI TEST UNIT READY IN stage */
|
||||||
if (EXIT_SUCCESS == mass_storage_send_scsi_csw_in())
|
if (EXIT_SUCCESS == mass_storage_send_scsi_csw_in())
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
/* Check for errors */
|
||||||
|
if (EXIT_SUCCESS != (error = mass_storage_check_error())) {
|
||||||
|
MASS_MSG("SCSI sense error checking failed");
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ignore potential signal interruption (no return value check),
|
||||||
|
* since it causes driver termination anyway */
|
||||||
|
if (nanosleep(&test_wait, NULL))
|
||||||
|
MASS_MSG("Calling nanosleep() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_FAILURE;
|
return EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* mass_storage_check_error *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
mass_storage_check_error(void)
|
||||||
|
{
|
||||||
|
/* SCSI sense structure for local use */
|
||||||
|
typedef struct MASS_PACKED scsi_sense {
|
||||||
|
|
||||||
|
uint8_t code : 7;
|
||||||
|
uint8_t valid : 1;
|
||||||
|
uint8_t obsolete : 8;
|
||||||
|
uint8_t sense : 4;
|
||||||
|
uint8_t reserved : 1;
|
||||||
|
uint8_t ili : 1;
|
||||||
|
uint8_t eom : 1;
|
||||||
|
uint8_t filemark : 1;
|
||||||
|
uint32_t information : 32;
|
||||||
|
uint8_t additional_len : 8;
|
||||||
|
uint32_t command_specific : 32;
|
||||||
|
uint8_t additional_code : 8;
|
||||||
|
uint8_t additional_qual : 8;
|
||||||
|
uint8_t unit_code : 8;
|
||||||
|
uint8_t key_specific1 : 7;
|
||||||
|
uint8_t sksv : 1;
|
||||||
|
uint16_t key_specific2 : 16;
|
||||||
|
}
|
||||||
|
scsi_sense;
|
||||||
|
|
||||||
|
/* Sense variable to hold received data */
|
||||||
|
scsi_sense sense;
|
||||||
|
|
||||||
|
MASS_DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Check if bit-fields are packed correctly */
|
||||||
|
__CTASSERT(sizeof(sense) == SCSI_REQUEST_SENSE_DATA_LEN);
|
||||||
|
|
||||||
|
/* SCSI REQUEST SENSE OUT stage */
|
||||||
|
if (mass_storage_send_scsi_cbw_out(SCSI_REQUEST_SENSE, NULL))
|
||||||
|
return EIO;
|
||||||
|
|
||||||
|
/* SCSI REQUEST SENSE first IN stage */
|
||||||
|
if (mass_storage_send_scsi_data_in(&sense, sizeof(sense)))
|
||||||
|
return EIO;
|
||||||
|
|
||||||
|
/* SCSI REQUEST SENSE second IN stage */
|
||||||
|
if (mass_storage_send_scsi_csw_in())
|
||||||
|
return EIO;
|
||||||
|
|
||||||
|
/* When any sense code is present something may have failed */
|
||||||
|
if (sense.sense) {
|
||||||
|
#ifdef MASS_DEBUG
|
||||||
|
MASS_MSG("SCSI sense: ");
|
||||||
|
MASS_MSG("code : %8X", sense.code );
|
||||||
|
MASS_MSG("valid : %8X", sense.valid );
|
||||||
|
MASS_MSG("obsolete : %8X", sense.obsolete );
|
||||||
|
MASS_MSG("sense : %8X", sense.sense );
|
||||||
|
MASS_MSG("reserved : %8X", sense.reserved );
|
||||||
|
MASS_MSG("ili : %8X", sense.ili );
|
||||||
|
MASS_MSG("eom : %8X", sense.eom );
|
||||||
|
MASS_MSG("filemark : %8X", sense.filemark );
|
||||||
|
MASS_MSG("information : %8X", sense.information );
|
||||||
|
MASS_MSG("additional_len : %8X", sense.additional_len );
|
||||||
|
MASS_MSG("command_specific : %8X", sense.command_specific);
|
||||||
|
MASS_MSG("additional_code : %8X", sense.additional_code );
|
||||||
|
MASS_MSG("additional_qual : %8X", sense.additional_qual );
|
||||||
|
MASS_MSG("unit_code : %8X", sense.unit_code );
|
||||||
|
MASS_MSG("key_specific1 : %8X", sense.key_specific1 );
|
||||||
|
MASS_MSG("sksv : %8X", sense.sksv );
|
||||||
|
MASS_MSG("key_specific2 : %8X", sense.key_specific2 );
|
||||||
|
#else
|
||||||
|
MASS_MSG("SCSI sense: 0x%02X 0x%02X 0x%02X", sense.sense,
|
||||||
|
sense.additional_code, sense.additional_qual);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1072,6 +1179,12 @@ mass_storage_open(devminor_t minor, int UNUSED(access))
|
||||||
if ((r = mass_storage_try_first_open())) {
|
if ((r = mass_storage_try_first_open())) {
|
||||||
MASS_MSG("Opening mass storage device"
|
MASS_MSG("Opening mass storage device"
|
||||||
" for the first time failed");
|
" for the first time failed");
|
||||||
|
|
||||||
|
/* Do one more test before failing, to output
|
||||||
|
* sense errors in case they weren't dumped already */
|
||||||
|
if (mass_storage_test())
|
||||||
|
MASS_MSG("Final TEST UNIT READY failed");
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1356,6 +1469,8 @@ mass_storage_part(devminor_t minor)
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* mass_storage_geometry *
|
* mass_storage_geometry *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
/* This command is optional for most mass storage devices
|
||||||
|
* It should rather be used with USB floppy disk reader */
|
||||||
#ifdef MASS_USE_GEOMETRY
|
#ifdef MASS_USE_GEOMETRY
|
||||||
static void
|
static void
|
||||||
mass_storage_geometry(devminor_t minor, struct part_geom * part)
|
mass_storage_geometry(devminor_t minor, struct part_geom * part)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# Makefile for the EARM USBD
|
# Makefile for the EARM USBD
|
||||||
|
|
||||||
PROG= usbd
|
PROG= usbd
|
||||||
SRCS= usbd.c usbd_earm.c hcd.c hcd_common.c hcd_ddekit.c musb_am335x.c musb_core.c
|
SRCS= usbd.c usbd_earm.c hcd.c hcd_common.c hcd_ddekit.c hcd_schedule.c musb_am335x.c musb_core.c
|
||||||
MAN=
|
MAN=
|
||||||
BINDIR= /service
|
BINDIR= /service
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
#include <minix/board.h>
|
#include <minix/board.h>
|
||||||
#include <minix/syslib.h>
|
#include <minix/syslib.h>
|
||||||
|
|
||||||
#include <usb/hcd_platforms.h>
|
#include <usbd/hcd_platforms.h>
|
||||||
#include <usb/usb_common.h>
|
#include <usbd/usbd_common.h>
|
||||||
#include <usb/usbd_interface.h>
|
#include <usbd/usbd_interface.h>
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
@ -10,8 +10,9 @@
|
||||||
#include <minix/devman.h> /* Initializing 'devman' */
|
#include <minix/devman.h> /* Initializing 'devman' */
|
||||||
#include <minix/sef.h> /* SEF handling */
|
#include <minix/sef.h> /* SEF handling */
|
||||||
|
|
||||||
#include <usb/usb_common.h>
|
#include <usbd/usbd_common.h>
|
||||||
#include <usb/usbd_interface.h>
|
#include <usbd/usbd_interface.h>
|
||||||
|
#include <usbd/usbd_schedule.h>
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -37,7 +38,7 @@ main(int UNUSED(argc), char * UNUSED(argv[]))
|
||||||
int ret_val;
|
int ret_val;
|
||||||
|
|
||||||
USB_MSG("Starting USBD");
|
USB_MSG("Starting USBD");
|
||||||
USB_DBG("Built: %s %s", __DATE__, __TIME__);
|
USB_MSG("Built: %s %s", __DATE__, __TIME__);
|
||||||
|
|
||||||
/* Basic SEF,DDE,... initialization */
|
/* Basic SEF,DDE,... initialization */
|
||||||
usbd_init();
|
usbd_init();
|
||||||
|
@ -74,7 +75,7 @@ main(int UNUSED(argc), char * UNUSED(argv[]))
|
||||||
static int
|
static int
|
||||||
usbd_sef_handler(int type, sef_init_info_t * UNUSED(info))
|
usbd_sef_handler(int type, sef_init_info_t * UNUSED(info))
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
/* No DEBUG_DUMP, threading unavailable yet */
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SEF_INIT_FRESH:
|
case SEF_INIT_FRESH:
|
||||||
|
@ -125,12 +126,21 @@ usbd_start(void)
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
/* Driver's "main loop" is within DDEKit server thread */
|
/* Driver's "main loop" is within DDEKit server thread */
|
||||||
usbd_th = ddekit_thread_create(usbd_server_thread, NULL, "USBD");
|
usbd_th = ddekit_thread_create(usbd_server_thread, NULL, "ddekit_usb");
|
||||||
|
|
||||||
/* After spawning, allow server thread to work */
|
/* After spawning, allow server thread to work */
|
||||||
if (NULL != usbd_th) {
|
if (NULL != usbd_th) {
|
||||||
/* This will lock current thread until DDEKit exits */
|
|
||||||
ddekit_minix_wait_exit();
|
/* Allow URB scheduling */
|
||||||
|
if (usbd_init_scheduler()) {
|
||||||
|
USB_MSG("Failed to start URB scheduler");
|
||||||
|
} else {
|
||||||
|
/* This will lock current thread until DDEKit exits */
|
||||||
|
ddekit_minix_wait_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disallow URB scheduling */
|
||||||
|
usbd_deinit_scheduler();
|
||||||
|
|
||||||
/* Cleanup */
|
/* Cleanup */
|
||||||
ddekit_thread_terminate(usbd_th);
|
ddekit_thread_terminate(usbd_th);
|
||||||
|
@ -147,16 +157,18 @@ usbd_start(void)
|
||||||
static void
|
static void
|
||||||
usbd_init(void)
|
usbd_init(void)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
/* No DEBUG_DUMP, threading unavailable yet */
|
||||||
|
|
||||||
/* Set one handler for all messages */
|
/* Set one handler for all messages */
|
||||||
sef_setcb_init_fresh(usbd_sef_handler);
|
sef_setcb_init_fresh(usbd_sef_handler);
|
||||||
sef_setcb_init_lu(usbd_sef_handler);
|
sef_setcb_init_lu(usbd_sef_handler);
|
||||||
sef_setcb_init_restart(usbd_sef_handler);
|
sef_setcb_init_restart(usbd_sef_handler);
|
||||||
sef_setcb_signal_handler(usbd_signal_handler);
|
|
||||||
|
|
||||||
/* Initialize DDEkit (involves sef_startup()) */
|
/* Initialize DDEkit (involves sef_startup()) */
|
||||||
ddekit_init();
|
ddekit_init();
|
||||||
|
|
||||||
|
/* After threading initialization, add signal handler */
|
||||||
|
sef_setcb_signal_handler(usbd_signal_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,18 +13,30 @@
|
||||||
#include <minix/clkconf.h> /* clkconf_* */
|
#include <minix/clkconf.h> /* clkconf_* */
|
||||||
#include <minix/syslib.h> /* sys_privctl */
|
#include <minix/syslib.h> /* sys_privctl */
|
||||||
|
|
||||||
#include <usb/hcd_common.h>
|
#include <usbd/hcd_common.h>
|
||||||
#include <usb/hcd_interface.h>
|
#include <usbd/hcd_interface.h>
|
||||||
#include <usb/usb_common.h>
|
#include <usbd/usbd_common.h>
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* Local prototypes *
|
* Local prototypes *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
/* Descriptor related operations */
|
||||||
static int hcd_fill_configuration(hcd_reg1 *, int, hcd_configuration *, int);
|
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_interface(hcd_reg1 *, int, hcd_interface *, int);
|
||||||
static int hcd_fill_endpoint(hcd_reg1 *, int, hcd_endpoint *);
|
static int hcd_fill_endpoint(hcd_reg1 *, int, hcd_endpoint *);
|
||||||
|
|
||||||
|
/* Handling free USB device addresses */
|
||||||
|
static hcd_reg1 hcd_reserve_addr(hcd_driver_state *);
|
||||||
|
static void hcd_release_addr(hcd_driver_state *, hcd_reg1);
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Local definitions *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* List of all allocated devices */
|
||||||
|
static hcd_device_state * dev_list = NULL;
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* hcd_os_interrupt_attach *
|
* hcd_os_interrupt_attach *
|
||||||
|
@ -188,49 +200,84 @@ hcd_os_nanosleep(int nanosec)
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* hcd_init_device *
|
* hcd_connect_device *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
int
|
int
|
||||||
hcd_connect_device(hcd_device_state * this_device, hcd_thread_function funct)
|
hcd_connect_device(hcd_device_state * this_device, hcd_thread_function funct)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
if ((NULL != this_device->lock) || (NULL != this_device->thread)) {
|
/* This is meant to allow thread name distinction
|
||||||
USB_MSG("Device data already allocated");
|
* and should not be used for anything else */
|
||||||
|
static unsigned int devnum = 0;
|
||||||
|
|
||||||
|
/* Should be able to hold device prefix and some number */
|
||||||
|
char devname[] = "dev..........";
|
||||||
|
|
||||||
|
USB_ASSERT((NULL == this_device->lock) &&
|
||||||
|
(NULL == this_device->thread) &&
|
||||||
|
(HCD_DEFAULT_ADDR == this_device->reserved_address) &&
|
||||||
|
(HCD_STATE_DISCONNECTED == this_device->state),
|
||||||
|
"Device structure not clean");
|
||||||
|
|
||||||
|
/* Mark as 'plugged in' to avoid treating device
|
||||||
|
* as 'disconnected' in case of errors below */
|
||||||
|
this_device->state = HCD_STATE_CONNECTION_PENDING;
|
||||||
|
|
||||||
|
/* Reserve device address for further use if available */
|
||||||
|
if (HCD_DEFAULT_ADDR == (this_device->reserved_address =
|
||||||
|
hcd_reserve_addr(this_device->driver))) {
|
||||||
|
USB_MSG("No free device addresses");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL == (this_device->lock = ddekit_sem_init(0)))
|
/* Get 'lock' that makes device thread wait for events to occur */
|
||||||
|
if (NULL == (this_device->lock = ddekit_sem_init(0))) {
|
||||||
|
USB_MSG("Failed to initialize thread lock");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prepare name */
|
||||||
|
snprintf(devname, sizeof(devname), "dev%u", devnum++);
|
||||||
|
|
||||||
|
/* Get thread itself */
|
||||||
if (NULL == (this_device->thread = ddekit_thread_create(funct,
|
if (NULL == (this_device->thread = ddekit_thread_create(funct,
|
||||||
this_device,
|
this_device,
|
||||||
"Device"))) {
|
(const char *)devname))) {
|
||||||
ddekit_sem_deinit(this_device->lock);
|
USB_MSG("Failed to initialize USB device thread");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow device thread to work */
|
|
||||||
ddekit_yield();
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* hcd_deinit_device *
|
* hcd_disconnect_device *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void
|
void
|
||||||
hcd_disconnect_device(hcd_device_state * this_device)
|
hcd_disconnect_device(hcd_device_state * this_device)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* TODO: This should disconnect all the children if they exist */
|
||||||
|
|
||||||
|
/* Clean configuration tree in case it was acquired */
|
||||||
hcd_tree_cleanup(&(this_device->config_tree));
|
hcd_tree_cleanup(&(this_device->config_tree));
|
||||||
|
|
||||||
ddekit_thread_terminate(this_device->thread);
|
/* Release allocated resources */
|
||||||
ddekit_sem_deinit(this_device->lock);
|
if (NULL != this_device->thread)
|
||||||
|
ddekit_thread_terminate(this_device->thread);
|
||||||
|
if (NULL != this_device->lock)
|
||||||
|
ddekit_sem_deinit(this_device->lock);
|
||||||
|
|
||||||
this_device->thread = NULL;
|
/* Release reserved address */
|
||||||
this_device->lock = NULL;
|
if (HCD_DEFAULT_ADDR != this_device->reserved_address)
|
||||||
|
hcd_release_addr(this_device->driver,
|
||||||
|
this_device->reserved_address);
|
||||||
|
|
||||||
|
/* Mark as disconnected */
|
||||||
|
this_device->state = HCD_STATE_DISCONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -238,20 +285,16 @@ hcd_disconnect_device(hcd_device_state * this_device)
|
||||||
* hcd_device_wait *
|
* hcd_device_wait *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void
|
void
|
||||||
hcd_device_wait(hcd_device_state * this_device, hcd_event event, hcd_reg1 ep)
|
hcd_device_wait(hcd_device_state * device, hcd_event event, hcd_reg1 ep)
|
||||||
{
|
{
|
||||||
hcd_driver_state * drv;
|
|
||||||
|
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
drv = (hcd_driver_state *)this_device->driver;
|
USB_DBG("0x%08X wait (0x%02X, 0x%02X)", device, event, ep);
|
||||||
|
|
||||||
drv->expected_event = event;
|
device->wait_event = event;
|
||||||
drv->expected_endpoint = ep;
|
device->wait_ep = ep;
|
||||||
|
|
||||||
USB_DBG("Waiting for: ev=0x%X, ep=0x%X", (int)event, ep);
|
ddekit_sem_down(device->lock);
|
||||||
|
|
||||||
ddekit_sem_down(this_device->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -259,25 +302,128 @@ hcd_device_wait(hcd_device_state * this_device, hcd_event event, hcd_reg1 ep)
|
||||||
* hcd_device_continue *
|
* hcd_device_continue *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void
|
void
|
||||||
hcd_device_continue(hcd_device_state * this_device)
|
hcd_device_continue(hcd_device_state * device, hcd_event event, hcd_reg1 ep)
|
||||||
{
|
{
|
||||||
hcd_driver_state * drv;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
USB_DBG("0x%08X continue (0x%02X, 0x%02X)", device, event, ep);
|
||||||
|
|
||||||
|
USB_ASSERT(device->wait_event == event, "Unexpected event");
|
||||||
|
USB_ASSERT(device->wait_ep == ep, "Unexpected endpoint");
|
||||||
|
|
||||||
|
ddekit_sem_up(device->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_new_device *
|
||||||
|
*===========================================================================*/
|
||||||
|
hcd_device_state *
|
||||||
|
hcd_new_device(void)
|
||||||
|
{
|
||||||
|
hcd_device_state * d;
|
||||||
|
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
drv = (hcd_driver_state *)this_device->driver;
|
/* One new blank device */
|
||||||
|
d = calloc(1, sizeof(*d));
|
||||||
|
|
||||||
/* We need to get what was expected... */
|
USB_ASSERT(NULL != d, "Failed to allocate device");
|
||||||
USB_ASSERT(drv->current_event == drv->expected_event,
|
|
||||||
"Unexpected event occurred");
|
|
||||||
|
|
||||||
/* ...including endpoint interrupts */
|
if (NULL == dev_list) {
|
||||||
if (HCD_EVENT_ENDPOINT == drv->current_event) {
|
dev_list = d;
|
||||||
USB_ASSERT(drv->current_endpoint == drv->expected_endpoint,
|
} else {
|
||||||
"Unexpected endpoint interrupt");
|
d->_next = dev_list;
|
||||||
|
dev_list = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
ddekit_sem_up(this_device->lock);
|
#ifdef HCD_DUMP_DEVICE_LIST
|
||||||
|
/* Dump updated state of device list */
|
||||||
|
hcd_dump_devices();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_delete_device *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_delete_device(hcd_device_state * d)
|
||||||
|
{
|
||||||
|
hcd_device_state * temp;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
if (d == dev_list) {
|
||||||
|
dev_list = dev_list->_next;
|
||||||
|
} else {
|
||||||
|
temp = dev_list;
|
||||||
|
|
||||||
|
/* Find the device and ... */
|
||||||
|
while (temp->_next != d) {
|
||||||
|
USB_ASSERT(NULL != temp->_next,
|
||||||
|
"Invalid state of device list");
|
||||||
|
temp = temp->_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ...make device list forget about it */
|
||||||
|
temp->_next = temp->_next->_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(d);
|
||||||
|
|
||||||
|
#ifdef HCD_DUMP_DEVICE_LIST
|
||||||
|
/* Dump updated state of device list */
|
||||||
|
hcd_dump_devices();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_dump_devices *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
hcd_dump_devices(void)
|
||||||
|
{
|
||||||
|
hcd_device_state * temp;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
temp = dev_list;
|
||||||
|
|
||||||
|
USB_MSG("Allocated devices:");
|
||||||
|
|
||||||
|
while (NULL != temp) {
|
||||||
|
USB_MSG("0x%08X", (int)temp);
|
||||||
|
temp = temp->_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_check_device *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
hcd_check_device(hcd_device_state * d)
|
||||||
|
{
|
||||||
|
hcd_device_state * temp;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
temp = dev_list;
|
||||||
|
|
||||||
|
/* Traverse the list of allocated devices
|
||||||
|
* to determine validity of this one */
|
||||||
|
while (NULL != temp) {
|
||||||
|
if (temp == d)
|
||||||
|
return EXIT_SUCCESS; /* Device found within the list */
|
||||||
|
temp = temp->_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Device was not found, may have been removed earlier */
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -571,3 +717,44 @@ hcd_fill_endpoint(hcd_reg1 * buf, int len, hcd_endpoint * e)
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_reserve_addr *
|
||||||
|
*===========================================================================*/
|
||||||
|
static hcd_reg1
|
||||||
|
hcd_reserve_addr(hcd_driver_state * driver)
|
||||||
|
{
|
||||||
|
hcd_reg1 addr;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
for (addr = HCD_FIRST_ADDR; addr <= HCD_LAST_ADDR; addr++) {
|
||||||
|
if (HCD_ADDR_AVAILABLE == driver->dev_addr[addr]) {
|
||||||
|
USB_DBG("Reserved address: %u", addr);
|
||||||
|
driver->dev_addr[addr] = HCD_ADDR_USED;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This means error */
|
||||||
|
return HCD_DEFAULT_ADDR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_release_addr *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_release_addr(hcd_driver_state * driver, hcd_reg1 addr)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
USB_ASSERT((addr > HCD_DEFAULT_ADDR) && (addr <= HCD_LAST_ADDR),
|
||||||
|
"Invalid device address to be released");
|
||||||
|
USB_ASSERT(HCD_ADDR_USED == driver->dev_addr[addr],
|
||||||
|
"Attempted to release unused address");
|
||||||
|
|
||||||
|
USB_DBG("Released address: %u", addr);
|
||||||
|
driver->dev_addr[addr] = HCD_ADDR_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
|
@ -6,9 +6,10 @@
|
||||||
|
|
||||||
#include <ddekit/usb.h>
|
#include <ddekit/usb.h>
|
||||||
|
|
||||||
#include <usb/hcd_ddekit.h>
|
#include <usbd/hcd_ddekit.h>
|
||||||
#include <usb/hcd_interface.h>
|
#include <usbd/hcd_interface.h>
|
||||||
#include <usb/usb_common.h>
|
#include <usbd/hcd_schedule.h>
|
||||||
|
#include <usbd/usbd_common.h>
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -16,7 +17,7 @@
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
/*
|
/*
|
||||||
* In this file "struct ddekit_usb_dev" equals "hcd_device_state"
|
* In this file "struct ddekit_usb_dev" equals "hcd_device_state"
|
||||||
* */
|
*/
|
||||||
struct ddekit_usb_device_id;
|
struct ddekit_usb_device_id;
|
||||||
struct ddekit_usb_urb;
|
struct ddekit_usb_urb;
|
||||||
struct ddekit_usb_dev;
|
struct ddekit_usb_dev;
|
||||||
|
@ -25,6 +26,13 @@ struct ddekit_usb_dev;
|
||||||
static void hcd_decode_urb(hcd_urb *, struct ddekit_usb_urb *);
|
static void hcd_decode_urb(hcd_urb *, struct ddekit_usb_urb *);
|
||||||
static void hcd_encode_urb(hcd_urb *, struct ddekit_usb_urb *);
|
static void hcd_encode_urb(hcd_urb *, struct ddekit_usb_urb *);
|
||||||
|
|
||||||
|
/* HCD's URB create/destroy */
|
||||||
|
static hcd_urb * hcd_new_urb(void);
|
||||||
|
static void hcd_free_urb(hcd_urb *);
|
||||||
|
|
||||||
|
/* Decodes event from received info */
|
||||||
|
static void hcd_decode_info(long, long, hcd_event *, hcd_reg1 *);
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* Global definitions *
|
* Global definitions *
|
||||||
|
@ -176,36 +184,19 @@ ddekit_usb_get_device_id(struct ddekit_usb_dev * dev,
|
||||||
int
|
int
|
||||||
ddekit_usb_submit_urb(struct ddekit_usb_urb * d_urb)
|
ddekit_usb_submit_urb(struct ddekit_usb_urb * d_urb)
|
||||||
{
|
{
|
||||||
hcd_device_state * dev;
|
hcd_urb * urb;
|
||||||
hcd_driver_state * drv;
|
|
||||||
|
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
/* Retrieve info on device/driver state from DDEKit's USB */
|
/* Get new URB */
|
||||||
dev = (hcd_device_state *)(d_urb->dev);
|
urb = hcd_new_urb();
|
||||||
drv = (hcd_driver_state *)(dev->driver);
|
|
||||||
|
|
||||||
/* Check for latest URB completion */
|
/* Turn DDEKit URB format to one that is easier to
|
||||||
if (NULL == dev->urb.original_urb) {
|
* handle by HCD, also check if URB is valid */
|
||||||
|
hcd_decode_urb(urb, d_urb);
|
||||||
|
|
||||||
/* Remember original URB */
|
/* Add URB to scheduler */
|
||||||
dev->urb.original_urb = (void *)d_urb;
|
return hcd_schedule_external_urb(urb);
|
||||||
|
|
||||||
/* TODO: If multiple URB's have to be queued, this code
|
|
||||||
* or DDEKit's must be altered accordingly */
|
|
||||||
/* Turn DDEKit URB format to one that is easier to
|
|
||||||
* handle by HCD, also check if URB is valid */
|
|
||||||
hcd_decode_urb(&(dev->urb), d_urb);
|
|
||||||
|
|
||||||
/* Start handling URB event */
|
|
||||||
drv->current_event = HCD_EVENT_URB;
|
|
||||||
hcd_handle_event(drv);
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Last URB must not have been completed */
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -218,10 +209,37 @@ ddekit_usb_cancle_urb(struct ddekit_usb_urb * d_urb)
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
/* TODO: UNUSED for argument won't work */
|
/* TODO: UNUSED for argument won't work */
|
||||||
((void)d_urb);
|
((void)d_urb);
|
||||||
|
/* TODO: No driver will require this any time soon */
|
||||||
|
USB_ASSERT(0, "URB cancellation not supported");
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* ddekit_usb_info *
|
||||||
|
*===========================================================================*/
|
||||||
|
long
|
||||||
|
ddekit_usb_info(struct ddekit_usb_dev * dev, long type, long value)
|
||||||
|
{
|
||||||
|
hcd_event event;
|
||||||
|
hcd_reg1 val;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Decode event */
|
||||||
|
hcd_decode_info(type, value, &event, &val);
|
||||||
|
|
||||||
|
if (HCD_EVENT_INVALID == event) {
|
||||||
|
USB_MSG("Invalid info message received");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
} else {
|
||||||
|
/* Let HCD handle info message */
|
||||||
|
hcd_handle_event((hcd_device_state *)dev, event, val);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* ddekit_usb_init *
|
* ddekit_usb_init *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
@ -290,13 +308,17 @@ hcd_completion_cb(hcd_urb * urb)
|
||||||
/* Recollect original URB */
|
/* Recollect original URB */
|
||||||
d_urb = (struct ddekit_usb_urb *)urb->original_urb;
|
d_urb = (struct ddekit_usb_urb *)urb->original_urb;
|
||||||
|
|
||||||
/* Turn HCD URB format to one handled by DDEKit */
|
/* Original URB will not be NULL if URB
|
||||||
hcd_encode_urb(urb, d_urb);
|
* was external (from device driver) */
|
||||||
|
if (NULL != d_urb) {
|
||||||
|
/* Turn HCD URB format to one handled by DDEKit */
|
||||||
|
hcd_encode_urb(urb, d_urb);
|
||||||
|
|
||||||
completion_cb(d_urb->priv);
|
/* No need for this URB anymore */
|
||||||
|
hcd_free_urb(urb);
|
||||||
|
|
||||||
/* URB was handled, forget about it */
|
completion_cb(d_urb->priv);
|
||||||
urb->original_urb = NULL;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -308,6 +330,9 @@ hcd_decode_urb(hcd_urb * urb, struct ddekit_usb_urb * dde_urb)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Remember original */
|
||||||
|
urb->original_urb = (void *)dde_urb;
|
||||||
|
|
||||||
/* No UBR error initially */
|
/* No UBR error initially */
|
||||||
urb->inout_status = EXIT_SUCCESS;
|
urb->inout_status = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
@ -397,7 +422,63 @@ hcd_encode_urb(hcd_urb * urb, struct ddekit_usb_urb * dde_urb)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Data buffers are the same, no need to copy */
|
||||||
/* Rewrite output for DDEKit part */
|
/* Rewrite output for DDEKit part */
|
||||||
dde_urb->actual_length = urb->out_size;
|
dde_urb->actual_length = urb->out_size;
|
||||||
dde_urb->status = urb->inout_status;
|
dde_urb->status = urb->inout_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_new_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
static hcd_urb *
|
||||||
|
hcd_new_urb(void)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
return malloc(sizeof(hcd_urb));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_free_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_free_urb(hcd_urb * urb)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
free(urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_decode_info *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_decode_info(long type, long invalue, hcd_event * event, hcd_reg1 * outvalue)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
USB_ASSERT((invalue >= 0) && (invalue <= 0xFF),
|
||||||
|
"Illegal USB info value received");
|
||||||
|
|
||||||
|
switch ((ddekit_msg_type_t)type) {
|
||||||
|
case DDEKIT_HUB_PORT_LS_CONN:
|
||||||
|
*event = HCD_EVENT_PORT_LS_CONNECTED;
|
||||||
|
break;
|
||||||
|
case DDEKIT_HUB_PORT_FS_CONN:
|
||||||
|
*event = HCD_EVENT_PORT_FS_CONNECTED;
|
||||||
|
break;
|
||||||
|
case DDEKIT_HUB_PORT_HS_CONN:
|
||||||
|
*event = HCD_EVENT_PORT_HS_CONNECTED;
|
||||||
|
break;
|
||||||
|
case DDEKIT_HUB_PORT_DISCONN:
|
||||||
|
*event = HCD_EVENT_PORT_DISCONNECTED;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*event = HCD_EVENT_INVALID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*outvalue = (hcd_reg1)invalue;
|
||||||
|
}
|
||||||
|
|
305
minix/drivers/usb/usbd/hcd/hcd_schedule.c
Normal file
305
minix/drivers/usb/usbd/hcd/hcd_schedule.c
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
/*
|
||||||
|
* Implementation of HCD URB scheduler
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h> /* memset */
|
||||||
|
|
||||||
|
#include <usbd/hcd_common.h>
|
||||||
|
#include <usbd/hcd_ddekit.h>
|
||||||
|
#include <usbd/hcd_interface.h>
|
||||||
|
#include <usbd/hcd_schedule.h>
|
||||||
|
#include <usbd/usbd_common.h>
|
||||||
|
#include <usbd/usbd_schedule.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* Required for scheduling *
|
||||||
|
*===========================================================================*/
|
||||||
|
/* TODO: Like in DDEKit but power of 2 */
|
||||||
|
#define HCD_MAX_URBS 16
|
||||||
|
|
||||||
|
/* TODO: Structure to hold URBs in DDEKit is limited so this is no better
|
||||||
|
* (but because of that, there is no need for another malloc) */
|
||||||
|
static hcd_urb * stored_urb[HCD_MAX_URBS];
|
||||||
|
|
||||||
|
/* Number of URBs stored during operation */
|
||||||
|
static int num_stored_urbs;
|
||||||
|
|
||||||
|
/* Scheduler thread */
|
||||||
|
static hcd_thread * urb_thread;
|
||||||
|
|
||||||
|
/* This allows waiting for URB */
|
||||||
|
static hcd_lock * urb_lock;
|
||||||
|
|
||||||
|
/* This allows waiting for completion */
|
||||||
|
static hcd_lock * handled_lock;
|
||||||
|
|
||||||
|
/* Makes URB schedule enabled */
|
||||||
|
static int hcd_schedule_urb(hcd_urb *);
|
||||||
|
|
||||||
|
/* Makes URB schedule disabled */
|
||||||
|
static void hcd_unschedule_urb(hcd_urb *);
|
||||||
|
|
||||||
|
/* Scheduler task */
|
||||||
|
static void hcd_urb_scheduler_task(void *);
|
||||||
|
|
||||||
|
/* Completion callback */
|
||||||
|
static void hcd_urb_handled(hcd_urb *);
|
||||||
|
|
||||||
|
/* Stores URB to be handled */
|
||||||
|
static int hcd_store_urb(hcd_urb *);
|
||||||
|
|
||||||
|
/* Removes stored URB */
|
||||||
|
static void hcd_remove_urb(hcd_urb *);
|
||||||
|
|
||||||
|
/* Gets URB to be handled next (based on priority) */
|
||||||
|
static hcd_urb * hcd_get_urb(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usbd_init_scheduler *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
usbd_init_scheduler(void)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Reset everything */
|
||||||
|
num_stored_urbs = 0;
|
||||||
|
memset(stored_urb, 0, sizeof(stored_urb));
|
||||||
|
|
||||||
|
urb_thread = ddekit_thread_create(hcd_urb_scheduler_task, NULL,
|
||||||
|
"scheduler");
|
||||||
|
if (NULL == urb_thread)
|
||||||
|
goto ERR1;
|
||||||
|
|
||||||
|
urb_lock = ddekit_sem_init(0);
|
||||||
|
if (NULL == urb_lock)
|
||||||
|
goto ERR2;
|
||||||
|
|
||||||
|
handled_lock = ddekit_sem_init(0);
|
||||||
|
if (NULL == handled_lock)
|
||||||
|
goto ERR3;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
ERR3:
|
||||||
|
ddekit_sem_deinit(urb_lock);
|
||||||
|
ERR2:
|
||||||
|
ddekit_thread_terminate(urb_thread);
|
||||||
|
ERR1:
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* usbd_deinit_scheduler *
|
||||||
|
*===========================================================================*/
|
||||||
|
void
|
||||||
|
usbd_deinit_scheduler(void)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
ddekit_sem_deinit(handled_lock);
|
||||||
|
|
||||||
|
ddekit_sem_deinit(urb_lock);
|
||||||
|
|
||||||
|
ddekit_thread_terminate(urb_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_schedule_external_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
hcd_schedule_external_urb(hcd_urb * urb)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
return hcd_schedule_urb(urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_schedule_internal_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
int
|
||||||
|
hcd_schedule_internal_urb(hcd_urb * urb)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
return hcd_schedule_urb(urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_schedule_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_schedule_urb(hcd_urb * urb)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* Tell URB what to call on completion */
|
||||||
|
urb->handled = hcd_urb_handled;
|
||||||
|
|
||||||
|
/* Store and check if scheduler should be unlocked */
|
||||||
|
if (EXIT_SUCCESS == hcd_store_urb(urb)) {
|
||||||
|
ddekit_sem_up(urb_lock);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_unschedule_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_unschedule_urb(hcd_urb * urb)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
hcd_remove_urb(urb);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_urb_scheduler_task *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_urb_scheduler_task(void * UNUSED(arg))
|
||||||
|
{
|
||||||
|
hcd_device_state * current_device;
|
||||||
|
hcd_urb * current_urb;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
/* Wait for scheduler to unlock on any URB submit */
|
||||||
|
ddekit_sem_down(urb_lock);
|
||||||
|
|
||||||
|
/* Get URB */
|
||||||
|
current_urb = hcd_get_urb();
|
||||||
|
|
||||||
|
/* Get URB's target device */
|
||||||
|
current_device = current_urb->target_device;
|
||||||
|
|
||||||
|
/* Check for mismatch */
|
||||||
|
USB_ASSERT(NULL != current_urb, "URB missing after URB unlock");
|
||||||
|
|
||||||
|
/* Check if URB's device is still allocated */
|
||||||
|
if (EXIT_SUCCESS == hcd_check_device(current_device)) {
|
||||||
|
/* Tell device that this is its URB */
|
||||||
|
current_device->urb = current_urb;
|
||||||
|
|
||||||
|
/* Start handling URB event */
|
||||||
|
hcd_handle_event(current_device, HCD_EVENT_URB,
|
||||||
|
HCD_UNUSED_VAL);
|
||||||
|
|
||||||
|
/* Wait for completion */
|
||||||
|
ddekit_sem_down(handled_lock);
|
||||||
|
|
||||||
|
/* TODO: Not enough DDEKit thread priorities
|
||||||
|
* for a better solution */
|
||||||
|
/* Yield, to allow unlocking thread, to continue
|
||||||
|
* before next URB is used */
|
||||||
|
ddekit_yield();
|
||||||
|
|
||||||
|
/* Makes thread debugging easier */
|
||||||
|
USB_DBG("URB handled, scheduler unlocked");
|
||||||
|
} else {
|
||||||
|
USB_MSG("Device 0x%08X for URB 0x%08X, is unavailable",
|
||||||
|
(int)current_device,
|
||||||
|
(int)current_urb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_urb_handled *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_urb_handled(hcd_urb * urb)
|
||||||
|
{
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* This URB will be scheduled no more */
|
||||||
|
hcd_unschedule_urb(urb);
|
||||||
|
|
||||||
|
/* Handling completed */
|
||||||
|
ddekit_sem_up(handled_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_store_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
static int
|
||||||
|
hcd_store_urb(hcd_urb * urb)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
for (i = 0; i < HCD_MAX_URBS; i++) {
|
||||||
|
if (NULL == stored_urb[i]) {
|
||||||
|
stored_urb[i] = urb;
|
||||||
|
num_stored_urbs++;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_MSG("No more free URBs");
|
||||||
|
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_remove_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
static void
|
||||||
|
hcd_remove_urb(hcd_urb * urb)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
for (i = 0; i < HCD_MAX_URBS; i++) {
|
||||||
|
if (urb == stored_urb[i]) {
|
||||||
|
stored_urb[i] = NULL;
|
||||||
|
num_stored_urbs--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
USB_ASSERT(0, "URB to be removed, was never stored");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================*
|
||||||
|
* hcd_get_urb *
|
||||||
|
*===========================================================================*/
|
||||||
|
static hcd_urb *
|
||||||
|
hcd_get_urb(void)
|
||||||
|
{
|
||||||
|
static int i = 0;
|
||||||
|
int checked;
|
||||||
|
|
||||||
|
DEBUG_DUMP;
|
||||||
|
|
||||||
|
/* TODO: Some priority checking may be here */
|
||||||
|
for (checked = 0; checked < HCD_MAX_URBS; checked++) {
|
||||||
|
/* To avoid starting from 0 every
|
||||||
|
* time (potential starvation) */
|
||||||
|
i = (i + 1) % HCD_MAX_URBS;
|
||||||
|
|
||||||
|
/* When found */
|
||||||
|
if (NULL != stored_urb[i])
|
||||||
|
return stored_urb[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nothing submitted yet */
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -4,10 +4,10 @@
|
||||||
|
|
||||||
#include <string.h> /* memset */
|
#include <string.h> /* memset */
|
||||||
|
|
||||||
#include <usb/hcd_common.h>
|
#include <usbd/hcd_common.h>
|
||||||
#include <usb/hcd_platforms.h>
|
#include <usbd/hcd_platforms.h>
|
||||||
#include <usb/hcd_interface.h>
|
#include <usbd/hcd_interface.h>
|
||||||
#include <usb/usb_common.h>
|
#include <usbd/usbd_common.h>
|
||||||
|
|
||||||
#include "musb_core.h"
|
#include "musb_core.h"
|
||||||
|
|
||||||
|
@ -348,6 +348,7 @@ musb_am335x_init(void)
|
||||||
ctrl->driver.out_status_stage = musb_out_status_stage;
|
ctrl->driver.out_status_stage = musb_out_status_stage;
|
||||||
ctrl->driver.read_data = musb_read_data;
|
ctrl->driver.read_data = musb_read_data;
|
||||||
ctrl->driver.check_error = musb_check_error;
|
ctrl->driver.check_error = musb_check_error;
|
||||||
|
ctrl->driver.port_device = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -388,6 +389,7 @@ musb_am335x_init(void)
|
||||||
ctrl->driver.out_status_stage = musb_out_status_stage;
|
ctrl->driver.out_status_stage = musb_out_status_stage;
|
||||||
ctrl->driver.read_data = musb_read_data;
|
ctrl->driver.read_data = musb_read_data;
|
||||||
ctrl->driver.check_error = musb_check_error;
|
ctrl->driver.check_error = musb_check_error;
|
||||||
|
ctrl->driver.port_device = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return musb_am335x_internal_init();
|
return musb_am335x_internal_init();
|
||||||
|
@ -563,25 +565,26 @@ musb_am335x_usbx_isr(void * data)
|
||||||
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED) {
|
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED) {
|
||||||
USB_DBG("Device connected");
|
USB_DBG("Device connected");
|
||||||
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED);
|
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_CONNECTED);
|
||||||
driver->current_event = HCD_EVENT_CONNECTED;
|
hcd_update_port(driver, HCD_EVENT_CONNECTED);
|
||||||
hcd_handle_event(driver);
|
hcd_handle_event(driver->port_device, HCD_EVENT_CONNECTED,
|
||||||
|
HCD_UNUSED_VAL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED) {
|
if (irqstat1 & AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED) {
|
||||||
USB_DBG("Device disconnected");
|
USB_DBG("Device disconnected");
|
||||||
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED);
|
CLEAR_IRQ1(AM335X_VAL_USBXIRQENABLEXXX1_DISCONNECTED);
|
||||||
driver->current_event = HCD_EVENT_DISCONNECTED;
|
hcd_handle_event(driver->port_device, HCD_EVENT_DISCONNECTED,
|
||||||
hcd_handle_event(driver);
|
HCD_UNUSED_VAL);
|
||||||
|
hcd_update_port(driver, HCD_EVENT_DISCONNECTED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 != irqstat0) {
|
if (0 != irqstat0) {
|
||||||
USB_DBG("EP interrupt");
|
USB_DBG("EP interrupt");
|
||||||
CLEAR_IRQ0(irqstat0);
|
CLEAR_IRQ0(irqstat0);
|
||||||
driver->current_event = HCD_EVENT_ENDPOINT;
|
hcd_handle_event(driver->port_device, HCD_EVENT_ENDPOINT,
|
||||||
driver->current_endpoint = musb_am335x_irqstat0_to_ep(irqstat0);
|
musb_am335x_irqstat0_to_ep(irqstat0));
|
||||||
hcd_handle_event(driver);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
#include <string.h> /* memcpy */
|
#include <string.h> /* memcpy */
|
||||||
|
|
||||||
#include <usb/hcd_common.h>
|
#include <usbd/hcd_common.h>
|
||||||
#include <usb/hcd_interface.h>
|
#include <usbd/hcd_interface.h>
|
||||||
#include <usb/usb_common.h>
|
#include <usbd/usbd_common.h>
|
||||||
|
|
||||||
#include "musb_core.h"
|
#include "musb_core.h"
|
||||||
#include "musb_regs.h"
|
#include "musb_regs.h"
|
||||||
|
@ -345,13 +345,16 @@ musb_core_stop(void * cfg)
|
||||||
* musb_setup_device *
|
* musb_setup_device *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
void
|
void
|
||||||
musb_setup_device(void * cfg, hcd_reg1 ep, hcd_reg1 addr)
|
musb_setup_device(void * cfg, hcd_reg1 ep, hcd_reg1 addr,
|
||||||
|
hcd_datatog * tx_tog, hcd_datatog * rx_tog)
|
||||||
{
|
{
|
||||||
DEBUG_DUMP;
|
DEBUG_DUMP;
|
||||||
|
|
||||||
/* Assign */
|
/* Assign */
|
||||||
((musb_core_config *)cfg)->ep = ep;
|
((musb_core_config *)cfg)->ep = ep;
|
||||||
((musb_core_config *)cfg)->addr = addr;
|
((musb_core_config *)cfg)->addr = addr;
|
||||||
|
((musb_core_config *)cfg)->datatog_tx = tx_tog;
|
||||||
|
((musb_core_config *)cfg)->datatog_rx = rx_tog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -372,7 +375,7 @@ musb_reset_device(void * cfg, hcd_speed * speed)
|
||||||
r = core->regs;
|
r = core->regs;
|
||||||
|
|
||||||
/* Set initial parameters */
|
/* Set initial parameters */
|
||||||
musb_setup_device(core, HCD_DEFAULT_EP, HCD_DEFAULT_ADDR);
|
musb_setup_device(core, HCD_DEFAULT_EP, HCD_DEFAULT_ADDR, NULL, NULL);
|
||||||
|
|
||||||
/* Set EP and device address to be used in this command */
|
/* Set EP and device address to be used in this command */
|
||||||
musb_set_state(core);
|
musb_set_state(core);
|
||||||
|
@ -408,9 +411,14 @@ musb_reset_device(void * cfg, hcd_speed * speed)
|
||||||
USB_DBG("High speed USB enabled");
|
USB_DBG("High speed USB enabled");
|
||||||
} else {
|
} else {
|
||||||
/* Only full-speed supported */
|
/* Only full-speed supported */
|
||||||
USB_DBG("High speed USB disabled");
|
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_FULL_SPEED);
|
||||||
|
HCD_WR1(r, MUSB_REG_HOST_TYPE0, host_type0);
|
||||||
|
|
||||||
*speed = HCD_SPEED_FULL;
|
*speed = HCD_SPEED_FULL;
|
||||||
|
|
||||||
|
USB_DBG("High speed USB disabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
@ -529,16 +537,16 @@ musb_rx_stage(void * cfg, hcd_datarequest * request)
|
||||||
|
|
||||||
/* Make controller reconfigure */
|
/* Make controller reconfigure */
|
||||||
host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
||||||
if (MUSB_DATATOG_UNKNOWN == core->datatog_rx[core->ep]) {
|
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_DATATOGWREN); /* Enable first */
|
||||||
/* Reset DATA toggle on first transfer */
|
|
||||||
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_CLRDATATOG);
|
|
||||||
core->datatog_rx[core->ep] = MUSB_DATATOG_INIT;
|
|
||||||
}
|
|
||||||
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_FLUSHFIFO);
|
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_FLUSHFIFO);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
|
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
|
||||||
|
|
||||||
/* Request packet */
|
/* Set data toggle and start receiving */
|
||||||
host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
host_rxcsr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
||||||
|
if (HCD_DATATOG_DATA0 == *(core->datatog_rx))
|
||||||
|
HCD_CLR(host_rxcsr, MUSB_VAL_HOST_RXCSR_DATATOG);
|
||||||
|
else
|
||||||
|
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_DATATOG);
|
||||||
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_REQPKT);
|
HCD_SET(host_rxcsr, MUSB_VAL_HOST_RXCSR_REQPKT);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
|
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_rxcsr);
|
||||||
}
|
}
|
||||||
|
@ -625,19 +633,20 @@ musb_tx_stage(void * cfg, hcd_datarequest * request)
|
||||||
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_MODE);
|
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_MODE);
|
||||||
HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_ISO);
|
HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_ISO);
|
||||||
HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_AUTOSET);
|
HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_AUTOSET);
|
||||||
if (MUSB_DATATOG_UNKNOWN == core->datatog_tx[core->ep]) {
|
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_DATATOGWREN); /* Enable first */
|
||||||
/* Reset DATA toggle on first transfer */
|
/* TODO: May have no effect */
|
||||||
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_CLRDATATOG);
|
|
||||||
core->datatog_tx[core->ep] = MUSB_DATATOG_INIT;
|
|
||||||
}
|
|
||||||
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO);
|
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
|
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
|
||||||
|
|
||||||
/* Put data in FIFO */
|
/* Put data in FIFO */
|
||||||
musb_write_fifo(cfg, request->data, request->data_left, core->ep);
|
musb_write_fifo(cfg, request->data, request->data_left, core->ep);
|
||||||
|
|
||||||
/* Request packet */
|
/* Set data toggle and start transmitting */
|
||||||
host_txcsr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
|
host_txcsr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
|
||||||
|
if (HCD_DATATOG_DATA0 == *(core->datatog_tx))
|
||||||
|
HCD_CLR(host_txcsr, MUSB_VAL_HOST_TXCSR_DATATOG);
|
||||||
|
else
|
||||||
|
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_DATATOG);
|
||||||
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_TXPKTRDY);
|
HCD_SET(host_txcsr, MUSB_VAL_HOST_TXCSR_TXPKTRDY);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
|
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_txcsr);
|
||||||
}
|
}
|
||||||
|
@ -785,6 +794,7 @@ musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
|
||||||
}
|
}
|
||||||
musb_error_case;
|
musb_error_case;
|
||||||
|
|
||||||
|
musb_core_config * core;
|
||||||
void * r;
|
void * r;
|
||||||
hcd_reg2 host_csr;
|
hcd_reg2 host_csr;
|
||||||
musb_error_case error_case;
|
musb_error_case error_case;
|
||||||
|
@ -795,7 +805,8 @@ musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
|
||||||
USB_ASSERT(HCD_TRANSFER_ISOCHRONOUS != xfer,
|
USB_ASSERT(HCD_TRANSFER_ISOCHRONOUS != xfer,
|
||||||
"ISO transfer not supported");
|
"ISO transfer not supported");
|
||||||
|
|
||||||
r = ((musb_core_config *)cfg)->regs;
|
core = (musb_core_config *)cfg;
|
||||||
|
r = core->regs;
|
||||||
|
|
||||||
/* Set EP and device address to be used in this command */
|
/* Set EP and device address to be used in this command */
|
||||||
musb_set_state((musb_core_config *)cfg);
|
musb_set_state((musb_core_config *)cfg);
|
||||||
|
@ -854,6 +865,13 @@ musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
|
||||||
/* Get TX status register */
|
/* Get TX status register */
|
||||||
host_csr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
|
host_csr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
|
||||||
|
|
||||||
|
/* Check for completion */
|
||||||
|
if (!(host_csr & MUSB_VAL_HOST_TXCSR_TXPKTRDY)) {
|
||||||
|
/* ACK received update data toggle */
|
||||||
|
*(core->datatog_tx) ^= HCD_DATATOG_DATA1;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for common errors */
|
/* Check for common errors */
|
||||||
if (host_csr & MUSB_VAL_HOST_TXCSR_ERROR) {
|
if (host_csr & MUSB_VAL_HOST_TXCSR_ERROR) {
|
||||||
USB_MSG("HOST_TXCSR ERROR: %04X", host_csr);
|
USB_MSG("HOST_TXCSR ERROR: %04X", host_csr);
|
||||||
|
@ -871,18 +889,30 @@ musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
|
||||||
|
|
||||||
if (host_csr & MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT) {
|
if (host_csr & MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT) {
|
||||||
USB_MSG("HOST_TXCSR NAK_TIMEOUT: %04X", host_csr);
|
USB_MSG("HOST_TXCSR NAK_TIMEOUT: %04X", host_csr);
|
||||||
|
/* Flush FIFO before clearing NAKTIMEOUT
|
||||||
|
* to abort transfer */
|
||||||
|
HCD_SET(host_csr, MUSB_VAL_HOST_TXCSR_FLUSHFIFO);
|
||||||
|
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
|
||||||
|
host_csr = HCD_RD2(r, MUSB_REG_HOST_TXCSR);
|
||||||
HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT);
|
HCD_CLR(host_csr, MUSB_VAL_HOST_TXCSR_NAK_TIMEOUT);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
|
HCD_WR2(r, MUSB_REG_HOST_TXCSR, host_csr);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
USB_ASSERT(0, "Invalid state of HOST_TXCSR");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MUSB_IN_ERROR_CASE == error_case) {
|
if (MUSB_IN_ERROR_CASE == error_case) {
|
||||||
/* Get RX status register */
|
/* Get RX status register */
|
||||||
host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
||||||
|
|
||||||
|
/* Check for completion */
|
||||||
|
if (host_csr & MUSB_VAL_HOST_RXCSR_RXPKTRDY) {
|
||||||
|
/* ACK received update data toggle */
|
||||||
|
*(core->datatog_rx) ^= HCD_DATATOG_DATA1;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for common errors */
|
/* Check for common errors */
|
||||||
if (host_csr & MUSB_VAL_HOST_RXCSR_ERROR) {
|
if (host_csr & MUSB_VAL_HOST_RXCSR_ERROR) {
|
||||||
USB_MSG("HOST_RXCSR ERROR: %04X", host_csr);
|
USB_MSG("HOST_RXCSR ERROR: %04X", host_csr);
|
||||||
|
@ -900,12 +930,16 @@ musb_check_error(void * cfg, hcd_transfer xfer, hcd_reg1 ep, hcd_direction dir)
|
||||||
|
|
||||||
if (host_csr & MUSB_VAL_HOST_RXCSR_NAKTIMEOUT) {
|
if (host_csr & MUSB_VAL_HOST_RXCSR_NAKTIMEOUT) {
|
||||||
USB_MSG("HOST_RXCSR NAK_TIMEOUT: %04X", host_csr);
|
USB_MSG("HOST_RXCSR NAK_TIMEOUT: %04X", host_csr);
|
||||||
|
/* Clear REQPKT before NAKTIMEOUT to abort transfer */
|
||||||
|
HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_REQPKT);
|
||||||
|
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
|
||||||
|
host_csr = HCD_RD2(r, MUSB_REG_HOST_RXCSR);
|
||||||
HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_NAKTIMEOUT);
|
HCD_CLR(host_csr, MUSB_VAL_HOST_RXCSR_NAKTIMEOUT);
|
||||||
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
|
HCD_WR2(r, MUSB_REG_HOST_RXCSR, host_csr);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
USB_ASSERT(0, "Invalid state of HOST_RXCSR");
|
||||||
}
|
}
|
||||||
|
|
||||||
USB_MSG("Invalid USB transfer error check: 0x%X, 0x%X, 0x%X",
|
USB_MSG("Invalid USB transfer error check: 0x%X, 0x%X, 0x%X",
|
||||||
|
|
|
@ -5,21 +5,12 @@
|
||||||
#ifndef _MUSB_CORE_H_
|
#ifndef _MUSB_CORE_H_
|
||||||
#define _MUSB_CORE_H_
|
#define _MUSB_CORE_H_
|
||||||
|
|
||||||
#include <usb/hcd_common.h>
|
#include <usbd/hcd_common.h>
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* Types and constants *
|
* Types and constants *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
/* Holds info on DATA toggle (DATA0/DATA1) initialization,
|
|
||||||
* required by bulk transfers */
|
|
||||||
typedef enum {
|
|
||||||
|
|
||||||
MUSB_DATATOG_UNKNOWN = 0, /* Default with memset 0 */
|
|
||||||
MUSB_DATATOG_INIT
|
|
||||||
}
|
|
||||||
musb_datatog;
|
|
||||||
|
|
||||||
/* Structure to hold Mentor USB core configuration
|
/* Structure to hold Mentor USB core configuration
|
||||||
* May be more than one on a single chip
|
* May be more than one on a single chip
|
||||||
* Should be initialized by MUSB's variant specific code (like AM335x) */
|
* Should be initialized by MUSB's variant specific code (like AM335x) */
|
||||||
|
@ -28,8 +19,8 @@ typedef struct {
|
||||||
void * regs; /* Points to beginning of memory mapped registers */
|
void * regs; /* Points to beginning of memory mapped registers */
|
||||||
hcd_reg1 ep; /* Currently used endpoint */
|
hcd_reg1 ep; /* Currently used endpoint */
|
||||||
hcd_reg1 addr; /* Currently used address */
|
hcd_reg1 addr; /* Currently used address */
|
||||||
musb_datatog datatog_tx[HCD_TOTAL_EP];
|
hcd_datatog * datatog_tx; /* Should point at currently used TX toggle */
|
||||||
musb_datatog datatog_rx[HCD_TOTAL_EP];
|
hcd_datatog * datatog_rx; /* Should point at currently used RX toggle */
|
||||||
}
|
}
|
||||||
musb_core_config;
|
musb_core_config;
|
||||||
|
|
||||||
|
@ -43,7 +34,8 @@ void musb_core_stop(void *);
|
||||||
|
|
||||||
|
|
||||||
/* For HCD interface */
|
/* For HCD interface */
|
||||||
void musb_setup_device(void *, hcd_reg1, hcd_reg1);
|
void musb_setup_device(void *, hcd_reg1, hcd_reg1,
|
||||||
|
hcd_datatog *, hcd_datatog *);
|
||||||
int musb_reset_device(void *, hcd_speed *);
|
int musb_reset_device(void *, hcd_speed *);
|
||||||
void musb_setup_stage(void *, hcd_ctrlrequest *);
|
void musb_setup_stage(void *, hcd_ctrlrequest *);
|
||||||
void musb_rx_stage(void *, hcd_datarequest *);
|
void musb_rx_stage(void *, hcd_datarequest *);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#ifndef _MUSB_REGS_H_
|
#ifndef _MUSB_REGS_H_
|
||||||
#define _MUSB_REGS_H_
|
#define _MUSB_REGS_H_
|
||||||
|
|
||||||
#include <usb/hcd_common.h>
|
#include <usbd/hcd_common.h>
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
|
|
@ -124,10 +124,15 @@ hcd_direction;
|
||||||
/* Possible asynchronous HCD events */
|
/* Possible asynchronous HCD events */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
||||||
HCD_EVENT_CONNECTED,
|
HCD_EVENT_CONNECTED = 0, /* Device connected directly to root */
|
||||||
HCD_EVENT_DISCONNECTED,
|
HCD_EVENT_DISCONNECTED, /* Directly connected device removed */
|
||||||
HCD_EVENT_ENDPOINT,
|
HCD_EVENT_PORT_LS_CONNECTED, /* Low speed device connected to hub */
|
||||||
HCD_EVENT_URB
|
HCD_EVENT_PORT_FS_CONNECTED, /* Full speed device connected to hub */
|
||||||
|
HCD_EVENT_PORT_HS_CONNECTED, /* High speed device connected to hub */
|
||||||
|
HCD_EVENT_PORT_DISCONNECTED, /* Device disconnected from hub */
|
||||||
|
HCD_EVENT_ENDPOINT, /* Something happened at endpoint */
|
||||||
|
HCD_EVENT_URB, /* URB was submitted by device driver */
|
||||||
|
HCD_EVENT_INVALID = 0xFF
|
||||||
}
|
}
|
||||||
hcd_event;
|
hcd_event;
|
||||||
|
|
||||||
|
@ -149,6 +154,14 @@ typedef enum {
|
||||||
}
|
}
|
||||||
hcd_speed;
|
hcd_speed;
|
||||||
|
|
||||||
|
/* Possible data toggle values (at least for bulk transfer) */
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
HCD_DATATOG_DATA0 = 0,
|
||||||
|
HCD_DATATOG_DATA1 = 1
|
||||||
|
}
|
||||||
|
hcd_datatog;
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* HCD threading/device/URB types *
|
* HCD threading/device/URB types *
|
||||||
|
@ -161,7 +174,14 @@ typedef struct usb_ctrlrequest hcd_ctrlrequest;
|
||||||
|
|
||||||
/* Largest value that can be transfered by this driver at a time
|
/* Largest value that can be transfered by this driver at a time
|
||||||
* see MAXPAYLOAD in TXMAXP/RXMAXP */
|
* see MAXPAYLOAD in TXMAXP/RXMAXP */
|
||||||
#define MAX_WTOTALLENGTH 1024
|
#define MAX_WTOTALLENGTH 1024u
|
||||||
|
|
||||||
|
/* TODO: This has corresponding redefinition in hub driver */
|
||||||
|
/* Limit of child devices for each parent */
|
||||||
|
#define HCD_CHILDREN 8u
|
||||||
|
|
||||||
|
/* Total number of endpoints available in USB 2.0 */
|
||||||
|
#define HCD_TOTAL_EP 16u
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
typedef struct hcd_datarequest hcd_datarequest;
|
typedef struct hcd_datarequest hcd_datarequest;
|
||||||
|
@ -189,6 +209,7 @@ struct hcd_urb {
|
||||||
/* Basic */
|
/* Basic */
|
||||||
void * original_urb;
|
void * original_urb;
|
||||||
hcd_device_state * target_device;
|
hcd_device_state * target_device;
|
||||||
|
void (*handled)(hcd_urb *); /* URB handled callback */
|
||||||
|
|
||||||
/* Transfer (in/out signifies what may be overwritten by HCD) */
|
/* Transfer (in/out signifies what may be overwritten by HCD) */
|
||||||
hcd_ctrlrequest * in_setup;
|
hcd_ctrlrequest * in_setup;
|
||||||
|
@ -207,18 +228,26 @@ struct hcd_urb {
|
||||||
/* Current state of attached device */
|
/* Current state of attached device */
|
||||||
struct hcd_device_state {
|
struct hcd_device_state {
|
||||||
|
|
||||||
hcd_driver_state * driver; /* Specific HCD driver object */
|
hcd_device_state * parent; /* In case of hub attachment */
|
||||||
|
hcd_device_state * child[HCD_CHILDREN]; /* In case of being hub */
|
||||||
|
hcd_device_state * _next; /* To allow device lists */
|
||||||
|
hcd_driver_state * driver; /* Specific HCD driver object */
|
||||||
hcd_thread * thread;
|
hcd_thread * thread;
|
||||||
hcd_lock * lock;
|
hcd_lock * lock;
|
||||||
void * data;
|
void * data;
|
||||||
|
|
||||||
hcd_urb urb;
|
hcd_urb * urb; /* URB to be used by device */
|
||||||
|
hcd_event wait_event; /* Expected event */
|
||||||
|
hcd_reg1 wait_ep; /* Expected event's endpoint */
|
||||||
hcd_device_descriptor device_desc;
|
hcd_device_descriptor device_desc;
|
||||||
hcd_configuration config_tree;
|
hcd_configuration config_tree;
|
||||||
hcd_reg1 max_packet_size;
|
hcd_reg1 max_packet_size;
|
||||||
hcd_speed speed;
|
hcd_speed speed;
|
||||||
hcd_state state;
|
hcd_state state;
|
||||||
hcd_reg1 address;
|
hcd_reg1 reserved_address;
|
||||||
|
hcd_reg1 current_address;
|
||||||
|
hcd_datatog ep_tx_tog[HCD_TOTAL_EP];
|
||||||
|
hcd_datatog ep_rx_tog[HCD_TOTAL_EP];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Control transfer's local data:
|
* Control transfer's local data:
|
||||||
|
@ -247,24 +276,24 @@ struct hcd_device_state {
|
||||||
#define HCD_DEFAULT_EP 0x00u
|
#define HCD_DEFAULT_EP 0x00u
|
||||||
#define HCD_DEFAULT_ADDR 0x00u
|
#define HCD_DEFAULT_ADDR 0x00u
|
||||||
#define HCD_DEFAULT_CONFIG 0x00u
|
#define HCD_DEFAULT_CONFIG 0x00u
|
||||||
|
#define HCD_FIRST_ADDR 0x01u
|
||||||
#define HCD_LAST_ADDR 0x7Fu
|
#define HCD_LAST_ADDR 0x7Fu
|
||||||
|
#define HCD_TOTAL_ADDR 0x80u
|
||||||
#define HCD_LAST_EP 0x0Fu
|
#define HCD_LAST_EP 0x0Fu
|
||||||
#define HCD_TOTAL_EP 0x10u
|
#define HCD_UNUSED_VAL 0xFFu /* When number not needed */
|
||||||
#define HCD_ANY_EP 0xFFu
|
#define HCD_DEFAULT_NAKLIMIT 0x10u
|
||||||
|
|
||||||
|
|
||||||
/* Legal interval values */
|
/* Legal interval values */
|
||||||
#define HCD_LOWEST_INTERVAL 0x00u
|
#define HCD_LOWEST_INTERVAL 0x00u
|
||||||
#define HCD_HIGHEST_INTERVAL 0xFFu
|
#define HCD_HIGHEST_INTERVAL 0xFFu
|
||||||
|
|
||||||
/* TODO: One device only */
|
|
||||||
#define HCD_ATTACHED_ADDR 0x01u
|
|
||||||
|
|
||||||
/* Translates configuration number for 'set configuration' */
|
/* Translates configuration number for 'set configuration' */
|
||||||
#define HCD_SET_CONFIG_NUM(num) ((num)+0x01u)
|
#define HCD_SET_CONFIG_NUM(num) ((num)+0x01u)
|
||||||
|
|
||||||
/* Default MaxPacketSize for control transfer */
|
/* Default MaxPacketSize for control transfer */
|
||||||
#define HCD_LS_MAXPACKETSIZE 8u
|
#define HCD_LS_MAXPACKETSIZE 8u /* Low-speed, Full-speed */
|
||||||
#define HCD_HS_MAXPACKETSIZE 64u
|
#define HCD_HS_MAXPACKETSIZE 64u /* High-speed */
|
||||||
#define HCD_MAX_MAXPACKETSIZE 1024u
|
#define HCD_MAX_MAXPACKETSIZE 1024u
|
||||||
|
|
||||||
|
|
||||||
|
@ -313,7 +342,13 @@ void hcd_disconnect_device(hcd_device_state *);
|
||||||
void hcd_device_wait(hcd_device_state *, hcd_event, hcd_reg1);
|
void hcd_device_wait(hcd_device_state *, hcd_event, hcd_reg1);
|
||||||
|
|
||||||
/* Unlocks device thread halted by 'hcd_device_wait' */
|
/* Unlocks device thread halted by 'hcd_device_wait' */
|
||||||
void hcd_device_continue(hcd_device_state *);
|
void hcd_device_continue(hcd_device_state *, hcd_event, hcd_reg1);
|
||||||
|
|
||||||
|
/* Allocation/deallocation of device structures */
|
||||||
|
hcd_device_state * hcd_new_device(void);
|
||||||
|
void hcd_delete_device(hcd_device_state *);
|
||||||
|
void hcd_dump_devices(void);
|
||||||
|
int hcd_check_device(hcd_device_state *);
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
|
@ -5,7 +5,7 @@
|
||||||
#ifndef _HCD_DDEKIT_H_
|
#ifndef _HCD_DDEKIT_H_
|
||||||
#define _HCD_DDEKIT_H_
|
#define _HCD_DDEKIT_H_
|
||||||
|
|
||||||
#include <usb/hcd_common.h>
|
#include <usbd/hcd_common.h>
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* External declarations *
|
* External declarations *
|
|
@ -2,13 +2,14 @@
|
||||||
* Interface for HCD
|
* Interface for HCD
|
||||||
*
|
*
|
||||||
* This file holds prototypes that must be implemented by HCD
|
* This file holds prototypes that must be implemented by HCD
|
||||||
* and event call that should be called when interrupt occurred
|
* and call that should be used for asynchronous events
|
||||||
|
* (interrupts, UBR submits, hub events, ...)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _HCD_INTERFACE_H_
|
#ifndef _HCD_INTERFACE_H_
|
||||||
#define _HCD_INTERFACE_H_
|
#define _HCD_INTERFACE_H_
|
||||||
|
|
||||||
#include <usb/hcd_common.h>
|
#include <usbd/hcd_common.h>
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -17,13 +18,22 @@
|
||||||
/* Can be returned by 'read_data' to indicate error */
|
/* Can be returned by 'read_data' to indicate error */
|
||||||
#define HCD_READ_ERR -1
|
#define HCD_READ_ERR -1
|
||||||
|
|
||||||
|
/* Possible states of USB device address */
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
HCD_ADDR_AVAILABLE = 0, /* Default for reset */
|
||||||
|
HCD_ADDR_USED
|
||||||
|
}
|
||||||
|
hcd_addr_state;
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* HCD driver structure to be filled
|
* HCD driver structure to be filled *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
struct hcd_driver_state {
|
struct hcd_driver_state {
|
||||||
/* Standard USB controller procedures */
|
/* Standard USB controller procedures */
|
||||||
void (*setup_device) (void *, hcd_reg1, hcd_reg1);
|
void (*setup_device) (void *, hcd_reg1, hcd_reg1,
|
||||||
|
hcd_datatog *, hcd_datatog *);
|
||||||
int (*reset_device) (void *, hcd_speed *);
|
int (*reset_device) (void *, hcd_speed *);
|
||||||
void (*setup_stage) (void *, hcd_ctrlrequest *);
|
void (*setup_stage) (void *, hcd_ctrlrequest *);
|
||||||
void (*rx_stage) (void *, hcd_datarequest *);
|
void (*rx_stage) (void *, hcd_datarequest *);
|
||||||
|
@ -39,20 +49,23 @@ struct hcd_driver_state {
|
||||||
/* Controller's private data (like mapped registers) */
|
/* Controller's private data (like mapped registers) */
|
||||||
void * private_data;
|
void * private_data;
|
||||||
|
|
||||||
/* Current state to be handled by driver */
|
/* TODO: Only one port for each driver */
|
||||||
hcd_event current_event;
|
/* Represents device attached to USB port handled by this driver */
|
||||||
hcd_reg1 current_endpoint;
|
hcd_device_state * port_device;
|
||||||
hcd_event expected_event;
|
|
||||||
hcd_reg1 expected_endpoint;
|
/* Array to hold information of unused device addresses */
|
||||||
|
hcd_addr_state dev_addr[HCD_TOTAL_ADDR];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* HCD event handling routine *
|
* HCD event handling routine *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
/* Handle asynchronous event
|
/* Handle asynchronous event */
|
||||||
* This must be called in case of specific HCD interrupts listed above */
|
void hcd_handle_event(hcd_device_state *, hcd_event, hcd_reg1);
|
||||||
void hcd_handle_event(hcd_driver_state *);
|
|
||||||
|
/* This resolves port's device structure for given driver and event */
|
||||||
|
void hcd_update_port(hcd_driver_state *, hcd_event);
|
||||||
|
|
||||||
|
|
||||||
#endif /* !_HCD_INTERFACE_H_ */
|
#endif /* !_HCD_INTERFACE_H_ */
|
16
minix/drivers/usb/usbd/include/usbd/hcd_schedule.h
Normal file
16
minix/drivers/usb/usbd/include/usbd/hcd_schedule.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* HCD URB scheduler interface
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _HCD_SCHEDULE_H_
|
||||||
|
#define _HCD_SCHEDULE_H_
|
||||||
|
|
||||||
|
#include <usbd/hcd_common.h>
|
||||||
|
|
||||||
|
/* Makes external (device driver) URB schedule enabled */
|
||||||
|
int hcd_schedule_external_urb(hcd_urb *);
|
||||||
|
|
||||||
|
/* Makes internal (HCD) URB schedule enabled */
|
||||||
|
int hcd_schedule_internal_urb(hcd_urb *);
|
||||||
|
|
||||||
|
#endif /* !_HCD_SCHEDULE_H_ */
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* Whatever is commonly used throughout USB code
|
* Whatever is commonly used throughout USBD code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _USB_COMMON_H_
|
#ifndef _USBD_COMMON_H_
|
||||||
#define _USB_COMMON_H_
|
#define _USBD_COMMON_H_
|
||||||
|
|
||||||
/* For commonly used: NULL, EXIT_*, and stuff like that */
|
/* For commonly used: NULL, EXIT_*, and stuff like that */
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -16,16 +16,23 @@
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* This allows us to analyze thread context in
|
||||||
|
* consecutive function calls (DEBUG_DUMP) */
|
||||||
|
#include <ddekit/thread.h>
|
||||||
|
|
||||||
|
/* Represents current thread's name string */
|
||||||
|
#define HCD_THREAD_NAME ddekit_thread_get_name(ddekit_thread_myself())
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* Standard output message *
|
* Standard output message *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
#define USB_MSG(fmt, ...) \
|
#define USB_MSG(fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
printf("USBD: "); \
|
printf("USBD: "); \
|
||||||
printf(fmt, ##__VA_ARGS__); \
|
printf(fmt, ##__VA_ARGS__); \
|
||||||
printf("\n"); \
|
printf("\n"); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
|
@ -33,16 +40,16 @@
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define DEBUG_DUMP \
|
#define DEBUG_DUMP \
|
||||||
do { \
|
do { \
|
||||||
printf("USBD (DEBUG %s)\n", __func__); \
|
printf("USBD: [%s -> %s]\n", HCD_THREAD_NAME, __func__);\
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define USB_DBG(fmt, ...) \
|
#define USB_DBG(fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
printf("USBD (DEBUG %s): ", __func__); \
|
printf("USBD: [%s -> %s] ", HCD_THREAD_NAME, __func__); \
|
||||||
printf(fmt, ##__VA_ARGS__); \
|
printf(fmt, ##__VA_ARGS__); \
|
||||||
printf("\n"); \
|
printf("\n"); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define DEBUG_DUMP ((void)0)
|
#define DEBUG_DUMP ((void)0)
|
||||||
|
@ -54,13 +61,14 @@
|
||||||
* Assert for USB code *
|
* Assert for USB code *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
#define USB_ASSERT(cond, otherwise) \
|
#define USB_ASSERT(cond, otherwise) \
|
||||||
do { \
|
do { \
|
||||||
if(!(cond)) { \
|
if (!(cond)) { \
|
||||||
USB_MSG("ASSERTION ERROR (%s:%d) - " \
|
USB_MSG("ASSERTION ERROR (%s -> %s:%d) - " \
|
||||||
otherwise, __func__, __LINE__); \
|
otherwise, HCD_THREAD_NAME, \
|
||||||
exit(EXIT_FAILURE); \
|
__func__, __LINE__); \
|
||||||
} \
|
exit(EXIT_FAILURE); \
|
||||||
} while(0)
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
#endif /* !_USB_COMMON_H_ */
|
#endif /* !_USBD_COMMON_H_ */
|
12
minix/drivers/usb/usbd/include/usbd/usbd_schedule.h
Normal file
12
minix/drivers/usb/usbd/include/usbd/usbd_schedule.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* USBD URB scheduler interface
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _USBD_SCHEDULE_H_
|
||||||
|
#define _USBD_SCHEDULE_H_
|
||||||
|
|
||||||
|
/* Should be used to create/destroy URB scheduler in base code */
|
||||||
|
int usbd_init_scheduler(void);
|
||||||
|
void usbd_deinit_scheduler(void);
|
||||||
|
|
||||||
|
#endif /* !_USBD_SCHEDULE_H_ */
|
|
@ -78,12 +78,23 @@ struct ddekit_usb_urb {
|
||||||
void *ddekit_priv;
|
void *ddekit_priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* USB message types */
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
DDEKIT_HUB_PORT_LS_CONN, /* Low speed device connected */
|
||||||
|
DDEKIT_HUB_PORT_FS_CONN, /* Full speed device connected */
|
||||||
|
DDEKIT_HUB_PORT_HS_CONN, /* High speed device connected */
|
||||||
|
DDEKIT_HUB_PORT_DISCONN /* Device disconnected */
|
||||||
|
}
|
||||||
|
ddekit_msg_type_t;
|
||||||
|
|
||||||
int ddekit_usb_dev_set_data(struct ddekit_usb_dev *dev, void *data);
|
int ddekit_usb_dev_set_data(struct ddekit_usb_dev *dev, void *data);
|
||||||
void *ddekit_usb_dev_get_data(struct ddekit_usb_dev *dev);
|
void *ddekit_usb_dev_get_data(struct ddekit_usb_dev *dev);
|
||||||
void ddekit_usb_get_device_id(struct ddekit_usb_dev *dev, struct
|
void ddekit_usb_get_device_id(struct ddekit_usb_dev *dev, struct
|
||||||
ddekit_usb_device_id *id);
|
ddekit_usb_device_id *id);
|
||||||
int ddekit_usb_submit_urb(struct ddekit_usb_urb *d_urb);
|
int ddekit_usb_submit_urb(struct ddekit_usb_urb *d_urb);
|
||||||
int ddekit_usb_cancle_urb(struct ddekit_usb_urb *d_urb);
|
int ddekit_usb_cancle_urb(struct ddekit_usb_urb *d_urb);
|
||||||
|
long ddekit_usb_info(struct ddekit_usb_dev *, long, long);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This one is only implemented for the client side. For the server side is
|
* This one is only implemented for the client side. For the server side is
|
||||||
|
|
|
@ -775,7 +775,8 @@
|
||||||
#define USB_RQ_DEINIT (USB_BASE + 1) /* Quit the session */
|
#define USB_RQ_DEINIT (USB_BASE + 1) /* Quit the session */
|
||||||
#define USB_RQ_SEND_URB (USB_BASE + 2) /* Send URB */
|
#define USB_RQ_SEND_URB (USB_BASE + 2) /* Send URB */
|
||||||
#define USB_RQ_CANCEL_URB (USB_BASE + 3) /* Cancel URB */
|
#define USB_RQ_CANCEL_URB (USB_BASE + 3) /* Cancel URB */
|
||||||
#define USB_REPLY (USB_BASE + 4)
|
#define USB_RQ_SEND_INFO (USB_BASE + 4) /* Sends various information */
|
||||||
|
#define USB_REPLY (USB_BASE + 5)
|
||||||
|
|
||||||
|
|
||||||
/* those are from USBD to driver */
|
/* those are from USBD to driver */
|
||||||
|
@ -793,6 +794,9 @@
|
||||||
# define USB_INTERFACES m4_l3
|
# define USB_INTERFACES m4_l3
|
||||||
# define USB_RB_INIT_NAME m3_ca1
|
# define USB_RB_INIT_NAME m3_ca1
|
||||||
|
|
||||||
|
# define USB_INFO_TYPE m4_l1
|
||||||
|
# define USB_INFO_VALUE m4_l2
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* Messages for DeviceManager (s/t like SysFS) *
|
* Messages for DeviceManager (s/t like SysFS) *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
|
|
@ -152,4 +152,7 @@ int usb_init(char *name);
|
||||||
/** This functions handles a message from the HCD */
|
/** This functions handles a message from the HCD */
|
||||||
int usb_handle_msg(struct usb_driver *ubd, message *msg);
|
int usb_handle_msg(struct usb_driver *ubd, message *msg);
|
||||||
|
|
||||||
|
/** Lets device driver send HCD various information */
|
||||||
|
int usb_send_info(long, long);
|
||||||
|
|
||||||
#endif /* _MINIX_USB_H */
|
#endif /* _MINIX_USB_H */
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
C_HERE=${NETBSDSRCDIR}/minix/lib/libc/arch/${ARCHSUBDIR}
|
C_HERE=${NETBSDSRCDIR}/minix/lib/libc/arch/${ARCHSUBDIR}
|
||||||
.PATH: ${C_HERE}
|
.PATH: ${C_HERE}
|
||||||
|
|
||||||
.warning looking into ${C_HERE}
|
|
||||||
|
|
||||||
SRCS+= _cpuid.S \
|
SRCS+= _cpuid.S \
|
||||||
get_bp.S \
|
get_bp.S \
|
||||||
getprocessor.S \
|
getprocessor.S \
|
||||||
|
|
|
@ -288,13 +288,13 @@ void _ddekit_interrupt_trigger(int irq_id)
|
||||||
irq_s = find_by_irq_id(irq_id);
|
irq_s = find_by_irq_id(irq_id);
|
||||||
|
|
||||||
if (irq_s) {
|
if (irq_s) {
|
||||||
DDEBUG_MSG_VERBOSE("Triggering IRQ %d", irq);
|
DDEBUG_MSG_VERBOSE("Triggering IRQ %d", irq_s->irq);
|
||||||
ddekit_sem_up(irq_s->sem);
|
ddekit_sem_up(irq_s->sem);
|
||||||
if (0 != (err_code = sys_irqenable(&irq_s->irq_hook)))
|
if (0 != (err_code = sys_irqenable(&irq_s->irq_hook)))
|
||||||
ddekit_panic("Failed to enable interrupt "
|
ddekit_panic("Failed to enable interrupt "
|
||||||
"(ERROR %d)", err_code);
|
"(ERROR %d)", err_code);
|
||||||
} else {
|
} else {
|
||||||
DDEBUG_MSG_WARN("no handler for IRQ %d", irq);
|
DDEBUG_MSG_WARN("no handler for IRQ %d", irq_s->irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -186,6 +186,17 @@ int ddekit_usb_cancle_urb(struct ddekit_usb_urb *d_urb)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* ddekit_usb_info *
|
||||||
|
*****************************************************************************/
|
||||||
|
long
|
||||||
|
ddekit_usb_info(struct ddekit_usb_dev * UNUSED(dev), long type, long value)
|
||||||
|
{
|
||||||
|
return usb_send_info(type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _ddekit_usb_thread()
|
static void _ddekit_usb_thread()
|
||||||
{
|
{
|
||||||
struct ddekit_minix_msg_q *mq = ddekit_minix_create_msg_q(USB_BASE,
|
struct ddekit_minix_msg_q *mq = ddekit_minix_create_msg_q(USB_BASE,
|
||||||
|
|
|
@ -71,6 +71,7 @@ static struct ddekit_usb_urb *ddekit_usb_urb_from_mx_urb(struct usb_urb
|
||||||
*mx_urb);
|
*mx_urb);
|
||||||
static void submit_urb(message *msg);
|
static void submit_urb(message *msg);
|
||||||
static void cancle_urb(message *msg);
|
static void cancle_urb(message *msg);
|
||||||
|
static void get_info(message *msg);
|
||||||
static void completion_callback(void *priv);
|
static void completion_callback(void *priv);
|
||||||
|
|
||||||
static void prepare_devman_usbdev(struct ddekit_usb_dev * dev, int
|
static void prepare_devman_usbdev(struct ddekit_usb_dev * dev, int
|
||||||
|
@ -441,6 +442,39 @@ static void cancle_urb(message *msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* get_info *
|
||||||
|
*****************************************************************************/
|
||||||
|
static void
|
||||||
|
get_info(message * msg)
|
||||||
|
{
|
||||||
|
struct minix_usb_driver * drv;
|
||||||
|
endpoint_t ep;
|
||||||
|
long info_type;
|
||||||
|
long info_value;
|
||||||
|
|
||||||
|
/* Read */
|
||||||
|
ep = msg->m_source;
|
||||||
|
info_type = msg->USB_INFO_TYPE;
|
||||||
|
info_value = msg->USB_INFO_VALUE;
|
||||||
|
|
||||||
|
/* Reuse as reply */
|
||||||
|
msg->m_type = USB_REPLY;
|
||||||
|
msg->USB_RESULT = -1;
|
||||||
|
|
||||||
|
/* Try and find driver first */
|
||||||
|
if (NULL == (drv = find_driver(ep)))
|
||||||
|
ddekit_printf("Non-registered driver tries to send info");
|
||||||
|
else
|
||||||
|
/* Route info to device */
|
||||||
|
msg->USB_RESULT = ddekit_usb_info(_devices[drv->dev].dev,
|
||||||
|
info_type, info_value);
|
||||||
|
|
||||||
|
/* Reply */
|
||||||
|
ipc_send(ep, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* completion_callback *
|
* completion_callback *
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
@ -713,6 +747,9 @@ static int handle_msg(message *msg)
|
||||||
case USB_RQ_CANCEL_URB:
|
case USB_RQ_CANCEL_URB:
|
||||||
cancle_urb(msg);
|
cancle_urb(msg);
|
||||||
return 1;
|
return 1;
|
||||||
|
case USB_RQ_SEND_INFO:
|
||||||
|
get_info(msg);
|
||||||
|
return 1;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,3 +223,32 @@ int usb_handle_msg(struct usb_driver *ud, message *msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* usb_send_info *
|
||||||
|
*****************************************************************************/
|
||||||
|
int
|
||||||
|
usb_send_info(long info_type, long info_value)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
message msg;
|
||||||
|
|
||||||
|
/* Prepare message */
|
||||||
|
msg.m_type = USB_RQ_SEND_INFO;
|
||||||
|
msg.USB_INFO_TYPE = info_type;
|
||||||
|
msg.USB_INFO_VALUE = info_value;
|
||||||
|
|
||||||
|
/* Send/receive message */
|
||||||
|
res = ipc_sendrec(hcd_ep, &msg);
|
||||||
|
|
||||||
|
if (res != 0)
|
||||||
|
panic("usb_send_info: could not talk to HCD: %d", res);
|
||||||
|
|
||||||
|
if (msg.m_type != USB_REPLY)
|
||||||
|
panic("usb_send_info: got illegal response from HCD: %d", msg.m_type);
|
||||||
|
|
||||||
|
if (msg.USB_RESULT != 0)
|
||||||
|
panic("usb_send_info: got illegal response from HCD: %d", msg.m_type);
|
||||||
|
|
||||||
|
return msg.USB_RESULT;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue