aboutsummaryrefslogtreecommitdiffstats
path: root/os
diff options
context:
space:
mode:
authorFabien Poussin <fabien.poussin@gmail.com>2017-06-07 11:26:30 +0200
committerGitHub <noreply@github.com>2017-06-07 11:26:30 +0200
commit46a0296ed6f68dd2a13f856ab2933a6a520af378 (patch)
tree6cf32e17ffc7890b3afac6fb2ef5e364a525576c /os
parent3ff5a092fcddcda4308d0220445c22e6847eb1db (diff)
parentf82de84347a64f4a826806696d23a61e60bd9115 (diff)
downloadChibiOS-Contrib-46a0296ed6f68dd2a13f856ab2933a6a520af378.tar.gz
ChibiOS-Contrib-46a0296ed6f68dd2a13f856ab2933a6a520af378.tar.bz2
ChibiOS-Contrib-46a0296ed6f68dd2a13f856ab2933a6a520af378.zip
Merge pull request #117 from dismirlian/usbh_devel
USB Host update
Diffstat (limited to 'os')
-rw-r--r--os/hal/hal.mk2
-rw-r--r--os/hal/include/hal_usbh.h33
-rw-r--r--os/hal/include/usbh/debug.h6
-rw-r--r--os/hal/include/usbh/defs.h43
-rw-r--r--os/hal/include/usbh/desciter.h4
-rw-r--r--os/hal/include/usbh/dev/aoa.h156
-rw-r--r--os/hal/include/usbh/dev/ftdi.h16
-rw-r--r--os/hal/include/usbh/dev/hid.h148
-rw-r--r--os/hal/include/usbh/dev/hub.h27
-rw-r--r--os/hal/include/usbh/dev/msd.h12
-rw-r--r--os/hal/include/usbh/dev/uvc.h471
-rw-r--r--os/hal/include/usbh/internal.h52
-rw-r--r--os/hal/include/usbh/list.h5
-rw-r--r--os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h934
-rw-r--r--os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c103
-rw-r--r--os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h17
-rw-r--r--os/hal/src/hal_usbh.c199
-rw-r--r--os/hal/src/usbh/hal_usbh_aoa.c678
-rw-r--r--os/hal/src/usbh/hal_usbh_debug.c13
-rw-r--r--os/hal/src/usbh/hal_usbh_desciter.c28
-rw-r--r--os/hal/src/usbh/hal_usbh_ftdi.c62
-rw-r--r--os/hal/src/usbh/hal_usbh_hid.c322
-rw-r--r--os/hal/src/usbh/hal_usbh_hub.c21
-rw-r--r--os/hal/src/usbh/hal_usbh_msd.c654
-rw-r--r--os/hal/src/usbh/hal_usbh_uvc.c659
-rw-r--r--os/various/fatfs_bindings/fatfs.mk7
-rw-r--r--os/various/fatfs_bindings/fatfs_diskio.c320
27 files changed, 3507 insertions, 1485 deletions
diff --git a/os/hal/hal.mk b/os/hal/hal.mk
index 79e501e..119db8a 100644
--- a/os/hal/hal.mk
+++ b/os/hal/hal.mk
@@ -12,6 +12,8 @@ HALSRC += ${CHIBIOS_CONTRIB}/os/hal/src/hal_community.c \
${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_hub.c \
${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_msd.c \
${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_ftdi.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_aoa.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_hid.c \
${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_uvc.c \
${CHIBIOS_CONTRIB}/os/hal/src/hal_ee24xx.c \
${CHIBIOS_CONTRIB}/os/hal/src/hal_ee25xx.c \
diff --git a/os/hal/include/hal_usbh.h b/os/hal/include/hal_usbh.h
index 63be93e..2684aca 100644
--- a/os/hal/include/hal_usbh.h
+++ b/os/hal/include/hal_usbh.h
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -20,6 +20,9 @@
#include "hal.h"
+#ifndef HAL_USE_USBH
+#define HAL_USE_USBH FALSE
+#endif
#ifndef HAL_USBH_USE_FTDI
#define HAL_USBH_USE_FTDI FALSE
@@ -37,6 +40,16 @@
#define HAL_USBH_USE_UVC FALSE
#endif
+#ifndef HAL_USBH_USE_AOA
+#define HAL_USBH_USE_AOA FALSE
+#endif
+
+#ifndef HAL_USBH_USE_HID
+#define HAL_USBH_USE_HID FALSE
+#endif
+
+#define HAL_USBH_USE_IAD HAL_USBH_USE_UVC
+
#if (HAL_USE_USBH == TRUE) || defined(__DOXYGEN__)
#include "osal.h"
@@ -104,13 +117,11 @@ enum usbh_urbstatus {
USBH_URBSTATUS_UNINITIALIZED = 0,
USBH_URBSTATUS_INITIALIZED,
USBH_URBSTATUS_PENDING,
-// USBH_URBSTATUS_QUEUED,
USBH_URBSTATUS_ERROR,
USBH_URBSTATUS_TIMEOUT,
USBH_URBSTATUS_CANCELLED,
USBH_URBSTATUS_STALL,
USBH_URBSTATUS_DISCONNECTED,
-// USBH_URBSTATUS_EPCLOSED,
USBH_URBSTATUS_OK,
};
@@ -145,7 +156,8 @@ typedef void (*usbh_completion_cb)(usbh_urb_t *);
/* include the low level driver; the required definitions are above */
#include "hal_usbh_lld.h"
-#define USBH_DEFINE_BUFFER(type, name) USBH_LLD_DEFINE_BUFFER(type, name)
+#define USBH_DEFINE_BUFFER(var) USBH_LLD_DEFINE_BUFFER(var)
+#define USBH_DECLARE_STRUCT_MEMBER(member) USBH_LLD_DECLARE_STRUCT_MEMBER(member)
struct usbh_urb {
usbh_ep_t *ep;
@@ -198,9 +210,8 @@ struct usbh_device {
usbh_devstatus_t status;
usbh_devspeed_t speed;
- USBH_DEFINE_BUFFER(usbh_device_descriptor_t, devDesc);
- unsigned char align_bytes[2];
- USBH_DEFINE_BUFFER(usbh_config_descriptor_t, basicConfigDesc);
+ USBH_DECLARE_STRUCT_MEMBER(usbh_device_descriptor_t devDesc);
+ USBH_DECLARE_STRUCT_MEMBER(usbh_config_descriptor_t basicConfigDesc);
uint8_t *fullConfigurationDescriptor;
uint8_t keepFullCfgDesc;
@@ -362,11 +373,7 @@ extern "C" {
usbhEPCloseS(ep);
osalSysUnlock();
}
- static inline void usbhEPResetI(usbh_ep_t *ep) {
- osalDbgCheckClassI();
- osalDbgCheck(ep != NULL);
- usbh_lld_epreset(ep);
- }
+ bool usbhEPReset(usbh_ep_t *ep);
static inline bool usbhEPIsPeriodic(usbh_ep_t *ep) {
osalDbgCheck(ep != NULL);
return (ep->type & 1) != 0;
diff --git a/os/hal/include/usbh/debug.h b/os/hal/include/usbh/debug.h
index 5120121..d3bdee7 100644
--- a/os/hal/include/usbh/debug.h
+++ b/os/hal/include/usbh/debug.h
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -23,8 +23,6 @@
#if HAL_USE_USBH
-//TODO: Debug is only for USBHD1, make it generic.
-
#if USBH_DEBUG_ENABLE
void usbDbgPrintf(const char *fmt, ...);
void usbDbgPuts(const char *s);
diff --git a/os/hal/include/usbh/defs.h b/os/hal/include/usbh/defs.h
index c3d8a9a..5e0c466 100644
--- a/os/hal/include/usbh/defs.h
+++ b/os/hal/include/usbh/defs.h
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -25,12 +25,12 @@
#include "osal.h"
#ifdef __IAR_SYSTEMS_ICC__
-#define PACKED_STRUCT typedef PACKED_VAR struct
+#define PACKED_STRUCT PACKED_VAR struct
#else
-#define PACKED_STRUCT typedef struct PACKED_VAR
+#define PACKED_STRUCT struct PACKED_VAR
#endif
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
@@ -49,7 +49,7 @@ PACKED_STRUCT {
#define USBH_DT_DEVICE 0x01
#define USBH_DT_DEVICE_SIZE 18
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
@@ -62,7 +62,7 @@ PACKED_STRUCT {
#define USBH_DT_CONFIG 0x02
#define USBH_DT_CONFIG_SIZE 9
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wData[1];
@@ -70,7 +70,7 @@ PACKED_STRUCT {
#define USBH_DT_STRING 0x03
#define USBH_DT_STRING_SIZE 2
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
@@ -84,7 +84,7 @@ PACKED_STRUCT {
#define USBH_DT_INTERFACE 0x04
#define USBH_DT_INTERFACE_SIZE 9
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
@@ -95,7 +95,7 @@ PACKED_STRUCT {
#define USBH_DT_ENDPOINT 0x05
#define USBH_DT_ENDPOINT_SIZE 7
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bFirstInterface;
@@ -108,7 +108,7 @@ PACKED_STRUCT {
#define USBH_DT_INTERFACE_ASSOCIATION 0x0b
#define USBH_DT_INTERFACE_ASSOCIATION_SIZE 8
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t bDescLength;
uint8_t bDescriptorType;
uint8_t bNbrPorts;
@@ -120,7 +120,7 @@ PACKED_STRUCT {
#define USBH_DT_HUB 0x29
#define USBH_DT_HUB_SIZE (7 + 4)
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
@@ -141,18 +141,17 @@ PACKED_STRUCT {
#define USBH_REQ_SET_INTERFACE 0x0B
#define USBH_REQ_SYNCH_FRAME 0x0C
+#define USBH_REQTYPE_DIR_IN 0x80
+#define USBH_REQTYPE_DIR_OUT 0x00
-#define USBH_REQTYPE_IN 0x80
-#define USBH_REQTYPE_OUT 0x00
+#define USBH_REQTYPE_TYPE_STANDARD 0x00
+#define USBH_REQTYPE_TYPE_CLASS 0x20
+#define USBH_REQTYPE_TYPE_VENDOR 0x40
-#define USBH_REQTYPE_STANDARD 0x00
-#define USBH_REQTYPE_CLASS 0x20
-#define USBH_REQTYPE_VENDOR 0x40
-
-#define USBH_REQTYPE_DEVICE 0x00
-#define USBH_REQTYPE_INTERFACE 0x01
-#define USBH_REQTYPE_ENDPOINT 0x02
-#define USBH_REQTYPE_OTHER 0x03
+#define USBH_REQTYPE_RECIP_DEVICE 0x00
+#define USBH_REQTYPE_RECIP_INTERFACE 0x01
+#define USBH_REQTYPE_RECIP_ENDPOINT 0x02
+#define USBH_REQTYPE_RECIP_OTHER 0x03
#endif
diff --git a/os/hal/include/usbh/desciter.h b/os/hal/include/usbh/desciter.h
index 52b0c98..142bd3c 100644
--- a/os/hal/include/usbh/desciter.h
+++ b/os/hal/include/usbh/desciter.h
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/os/hal/include/usbh/dev/aoa.h b/os/hal/include/usbh/dev/aoa.h
new file mode 100644
index 0000000..636768a
--- /dev/null
+++ b/os/hal/include/usbh/dev/aoa.h
@@ -0,0 +1,156 @@
+/*
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef USBH_AOA_H_
+#define USBH_AOA_H_
+
+#include "hal_usbh.h"
+
+#if HAL_USE_USBH && HAL_USBH_USE_AOA
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+typedef enum {
+ USBHAOA_CHANNEL_STATE_UNINIT = 0,
+ USBHAOA_CHANNEL_STATE_STOP = 1,
+ USBHAOA_CHANNEL_STATE_ACTIVE = 2,
+ USBHAOA_CHANNEL_STATE_READY = 3
+} usbhaoa_channel_state_t;
+
+typedef enum {
+ USBHAOA_STATE_UNINIT = 0,
+ USBHAOA_STATE_STOP = 1,
+ USBHAOA_STATE_ACTIVE = 2,
+ USBHAOA_STATE_READY = 3
+} usbhaoa_state_t;
+
+typedef enum {
+ USBHAOA_AUDIO_MODE_DISABLED = 0,
+ USBHAOA_AUDIO_MODE_2CH_16BIT_PCM_44100 = 1,
+} usbhaoa_audio_mode_t;
+
+typedef struct {
+ struct _aoa_channel_cfg {
+ const char *manufacturer;
+ const char *model;
+ const char *description;
+ const char *version;
+ const char *uri;
+ const char *serial;
+ } channel;
+
+ struct _aoa_audio_cfg {
+ usbhaoa_audio_mode_t mode;
+ } audio;
+
+} USBHAOAConfig;
+
+#define _aoa_driver_methods \
+ _base_asynchronous_channel_methods
+
+struct AOADriverVMT {
+ _aoa_driver_methods
+};
+
+typedef struct USBHAOAChannel USBHAOAChannel;
+typedef struct USBHAOADriver USBHAOADriver;
+
+struct USBHAOAChannel {
+ /* inherited from abstract asyncrhonous channel driver */
+ const struct AOADriverVMT *vmt;
+ _base_asynchronous_channel_data
+
+ usbh_ep_t epin;
+ usbh_urb_t iq_urb;
+ threads_queue_t iq_waiting;
+ uint32_t iq_counter;
+ USBH_DECLARE_STRUCT_MEMBER(uint8_t iq_buff[64]);
+ uint8_t *iq_ptr;
+
+ usbh_ep_t epout;
+ usbh_urb_t oq_urb;
+ threads_queue_t oq_waiting;
+ uint32_t oq_counter;
+ USBH_DECLARE_STRUCT_MEMBER(uint8_t oq_buff[64]);
+ uint8_t *oq_ptr;
+
+ virtual_timer_t vt;
+
+ usbhaoa_channel_state_t state;
+};
+
+struct USBHAOADriver {
+ /* inherited from abstract class driver */
+ _usbh_base_classdriver_data
+
+ USBHAOAChannel channel;
+
+ usbhaoa_state_t state;
+
+};
+
+#define USBHAOA_ACCESSORY_STRING_MANUFACTURER 0
+#define USBHAOA_ACCESSORY_STRING_MODEL 1
+#define USBHAOA_ACCESSORY_STRING_DESCRIPTION 2
+#define USBHAOA_ACCESSORY_STRING_VERSION 3
+#define USBHAOA_ACCESSORY_STRING_URI 4
+#define USBHAOA_ACCESSORY_STRING_SERIAL 5
+
+typedef bool (*usbhaoa_filter_callback_t)(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem, USBHAOAConfig *config);
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+#define usbhaoaStop(aoap)
+
+#define usbhaoaGetState(aoap) ((aoap)->state)
+
+#define usbhaoaGetChannelState(aoap) ((aoap)->channel.state)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+extern USBHAOADriver USBHAOAD[HAL_USBHAOA_MAX_INSTANCES];
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /* AOA device driver */
+ void usbhaoaObjectInit(USBHAOADriver *aoap);
+ void usbhaoaChannelStart(USBHAOADriver *aoap);
+ void usbhaoaChannelStop(USBHAOADriver *aoap);
+
+ /* global initializer */
+ void usbhaoaInit(void);
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
+#endif /* USBH_AOA_H_ */
diff --git a/os/hal/include/usbh/dev/ftdi.h b/os/hal/include/usbh/dev/ftdi.h
index ad6b4cd..bfa3103 100644
--- a/os/hal/include/usbh/dev/ftdi.h
+++ b/os/hal/include/usbh/dev/ftdi.h
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -96,7 +96,7 @@ struct USBHFTDIPortDriver {
usbh_urb_t iq_urb;
threads_queue_t iq_waiting;
uint32_t iq_counter;
- USBH_DEFINE_BUFFER(uint8_t, iq_buff[64]);
+ USBH_DECLARE_STRUCT_MEMBER(uint8_t iq_buff[64]);
uint8_t *iq_ptr;
@@ -104,7 +104,7 @@ struct USBHFTDIPortDriver {
usbh_urb_t oq_urb;
threads_queue_t oq_waiting;
uint32_t oq_counter;
- USBH_DEFINE_BUFFER(uint8_t, oq_buff[64]);
+ USBH_DECLARE_STRUCT_MEMBER(uint8_t oq_buff[64]);
uint8_t *oq_ptr;
virtual_timer_t vt;
@@ -113,7 +113,7 @@ struct USBHFTDIPortDriver {
USBHFTDIPortDriver *next;
};
-typedef struct USBHFTDIDriver {
+struct USBHFTDIDriver {
/* inherited from abstract class driver */
_usbh_base_classdriver_data
@@ -121,11 +121,12 @@ typedef struct USBHFTDIDriver {
USBHFTDIPortDriver *ports;
mutex_t mtx;
-} USBHFTDIDriver;
+};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
+#define usbhftdipGetState(ftdipp) ((ftdipp)->state)
/*===========================================================================*/
@@ -144,6 +145,9 @@ extern "C" {
void usbhftdipObjectInit(USBHFTDIPortDriver *ftdipp);
void usbhftdipStart(USBHFTDIPortDriver *ftdipp, const USBHFTDIPortConfig *config);
void usbhftdipStop(USBHFTDIPortDriver *ftdipp);
+
+ /* global initializer */
+ void usbhftdiInit(void);
#ifdef __cplusplus
}
#endif
diff --git a/os/hal/include/usbh/dev/hid.h b/os/hal/include/usbh/dev/hid.h
new file mode 100644
index 0000000..0d6b894
--- /dev/null
+++ b/os/hal/include/usbh/dev/hid.h
@@ -0,0 +1,148 @@
+/*
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#ifndef USBH_HID_H_
+#define USBH_HID_H_
+
+#include "hal_usbh.h"
+
+#if HAL_USE_USBH && HAL_USBH_USE_HID
+
+/* TODO:
+ *
+ */
+
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+#if !defined(HAL_USBHHID_USE_INTERRUPT_OUT)
+#define HAL_USBHHID_USE_INTERRUPT_OUT FALSE
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+typedef enum {
+ USBHHID_STATE_UNINIT = 0,
+ USBHHID_STATE_STOP = 1,
+ USBHHID_STATE_ACTIVE = 2,
+ USBHHID_STATE_READY = 3
+} usbhhid_state_t;
+
+typedef enum {
+ USBHHID_DEVTYPE_GENERIC = 0,
+ USBHHID_DEVTYPE_BOOT_KEYBOARD = 1,
+ USBHHID_DEVTYPE_BOOT_MOUSE = 2,
+} usbhhid_devtype_t;
+
+typedef enum {
+ USBHHID_REPORTTYPE_INPUT = 1,
+ USBHHID_REPORTTYPE_OUTPUT = 2,
+ USBHHID_REPORTTYPE_FEATURE = 3,
+} usbhhid_reporttype_t;
+
+typedef enum {
+ USBHHID_PROTOCOL_BOOT = 0,
+ USBHHID_PROTOCOL_REPORT = 1,
+} usbhhid_protocol_t;
+
+typedef struct USBHHIDDriver USBHHIDDriver;
+typedef struct USBHHIDConfig USBHHIDConfig;
+
+typedef void (*usbhhid_report_callback)(USBHHIDDriver *hidp, uint16_t len);
+
+struct USBHHIDConfig {
+ usbhhid_report_callback cb_report;
+ void *report_buffer;
+ uint16_t report_len;
+ usbhhid_protocol_t protocol;
+};
+
+struct USBHHIDDriver {
+ /* inherited from abstract class driver */
+ _usbh_base_classdriver_data
+
+ usbh_ep_t epin;
+#if HAL_USBHHID_USE_INTERRUPT_OUT
+ usbh_ep_t epout;
+#endif
+ uint8_t ifnum;
+
+ usbhhid_devtype_t type;
+ usbhhid_state_t state;
+
+ usbh_urb_t in_urb;
+
+ const USBHHIDConfig *config;
+};
+
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+extern USBHHIDDriver USBHHIDD[HAL_USBHHID_MAX_INSTANCES];
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /* HID Driver */
+ void usbhHIDObjectInit(USBHHIDDriver *hidp);
+
+ /* HID Common API */
+ usbh_urbstatus_t usbhhidGetReport(USBHHIDDriver *hidp,
+ uint8_t report_id, usbhhid_reporttype_t report_type,
+ void *data, uint16_t len);
+ usbh_urbstatus_t usbhhidSetReport(USBHHIDDriver *hidp,
+ uint8_t report_id, usbhhid_reporttype_t report_type,
+ const void *data, uint16_t len);
+ usbh_urbstatus_t usbhhidGetIdle(USBHHIDDriver *hidp, uint8_t report_id, uint8_t *duration);
+ usbh_urbstatus_t usbhhidSetIdle(USBHHIDDriver *hidp, uint8_t report_id, uint8_t duration);
+ usbh_urbstatus_t usbhhidGetProtocol(USBHHIDDriver *hidp, uint8_t *protocol);
+ usbh_urbstatus_t usbhhidSetProtocol(USBHHIDDriver *hidp, uint8_t protocol);
+
+ static inline uint8_t usbhhidGetType(USBHHIDDriver *hidp) {
+ return hidp->type;
+ }
+
+ static inline usbhhid_state_t usbhhidGetState(USBHHIDDriver *hidp) {
+ return hidp->state;
+ }
+
+ void usbhhidStart(USBHHIDDriver *hidp, const USBHHIDConfig *cfg);
+
+ /* global initializer */
+ void usbhhidInit(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif /* USBH_HID_H_ */
diff --git a/os/hal/include/usbh/dev/hub.h b/os/hal/include/usbh/dev/hub.h
index 07e88e6..924ebec 100644
--- a/os/hal/include/usbh/dev/hub.h
+++ b/os/hal/include/usbh/dev/hub.h
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
#if HAL_USE_USBH
#if HAL_USBH_USE_HUB
-typedef struct USBHHubDriver {
+struct USBHHubDriver {
/* inherited from abstract class driver */
_usbh_base_classdriver_data
@@ -32,19 +32,19 @@ typedef struct USBHHubDriver {
usbh_ep_t epint;
usbh_urb_t urb;
- USBH_DEFINE_BUFFER(uint8_t, scbuff[4]);
+ USBH_DECLARE_STRUCT_MEMBER(uint8_t scbuff[4]);
volatile uint32_t statuschange;
uint16_t status;
uint16_t c_status;
usbh_port_t *ports;
- USBH_DEFINE_BUFFER(usbh_hub_descriptor_t, hubDesc);
+ USBH_DECLARE_STRUCT_MEMBER(usbh_hub_descriptor_t hubDesc);
/* Low level part */
_usbh_hub_ll_data
-} USBHHubDriver;
+};
extern USBHHubDriver USBHHUBD[HAL_USBHHUB_MAX_INSTANCES];
@@ -60,7 +60,7 @@ usbh_urbstatus_t usbhhubControlRequest(USBHDriver *host, USBHHubDriver *hub,
static inline usbh_urbstatus_t usbhhubClearFeaturePort(usbh_port_t *port, uint8_t feature) {
return usbhhubControlRequest(port->device.host, port->hub,
- USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
+ USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_OTHER,
USBH_REQ_CLEAR_FEATURE,
feature,
port->number,
@@ -70,7 +70,7 @@ static inline usbh_urbstatus_t usbhhubClearFeaturePort(usbh_port_t *port, uint8_
static inline usbh_urbstatus_t usbhhubClearFeatureHub(USBHDriver *host, USBHHubDriver *hub, uint8_t feature) {
return usbhhubControlRequest(host, hub,
- USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE,
+ USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_DEVICE,
USBH_REQ_CLEAR_FEATURE,
feature,
0,
@@ -80,7 +80,7 @@ static inline usbh_urbstatus_t usbhhubClearFeatureHub(USBHDriver *host, USBHHubD
static inline usbh_urbstatus_t usbhhubSetFeaturePort(usbh_port_t *port, uint8_t feature) {
return usbhhubControlRequest(port->device.host, port->hub,
- USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
+ USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_OTHER,
USBH_REQ_SET_FEATURE,
feature,
port->number,
@@ -89,6 +89,9 @@ static inline usbh_urbstatus_t usbhhubSetFeaturePort(usbh_port_t *port, uint8_t
}
void usbhhubObjectInit(USBHHubDriver *hubdp);
+
+void usbhhubInit(void);
+
#else
static inline usbh_urbstatus_t usbhhubControlRequest(USBHDriver *host,
@@ -103,7 +106,7 @@ static inline usbh_urbstatus_t usbhhubControlRequest(USBHDriver *host,
static inline usbh_urbstatus_t usbhhubClearFeaturePort(usbh_port_t *port, uint8_t feature) {
return usbhhubControlRequest(port->device.host,
- USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
+ USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_OTHER,
USBH_REQ_CLEAR_FEATURE,
feature,
port->number,
@@ -113,7 +116,7 @@ static inline usbh_urbstatus_t usbhhubClearFeaturePort(usbh_port_t *port, uint8_
static inline usbh_urbstatus_t usbhhubClearFeatureHub(USBHDriver *host, uint8_t feature) {
return usbhhubControlRequest(host,
- USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE,
+ USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_DEVICE,
USBH_REQ_CLEAR_FEATURE,
feature,
0,
@@ -123,7 +126,7 @@ static inline usbh_urbstatus_t usbhhubClearFeatureHub(USBHDriver *host, uint8_t
static inline usbh_urbstatus_t usbhhubSetFeaturePort(usbh_port_t *port, uint8_t feature) {
return usbhhubControlRequest(port->device.host,
- USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
+ USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_OTHER,
USBH_REQ_SET_FEATURE,
feature,
port->number,
diff --git a/os/hal/include/usbh/dev/msd.h b/os/hal/include/usbh/dev/msd.h
index d164618..84179c5 100644
--- a/os/hal/include/usbh/dev/msd.h
+++ b/os/hal/include/usbh/dev/msd.h
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@
/* TODO:
*
* - Implement of conditional compilation of multiple-luns per instance.
- * - Implement error checking and recovery when commands fail.
*
*/
@@ -65,7 +64,7 @@ struct USBHMassStorageLUNDriver {
USBHMassStorageLUNDriver *next;
};
-typedef struct USBHMassStorageDriver {
+struct USBHMassStorageDriver {
/* inherited from abstract class driver */
_usbh_base_classdriver_data
@@ -81,7 +80,7 @@ typedef struct USBHMassStorageDriver {
uint32_t tag;
USBHMassStorageLUNDriver *luns;
-} USBHMassStorageDriver;
+};
/*===========================================================================*/
@@ -116,6 +115,9 @@ extern "C" {
bool usbhmsdLUNGetInfo(USBHMassStorageLUNDriver *lunp, BlockDeviceInfo *bdip);
bool usbhmsdLUNIsInserted(USBHMassStorageLUNDriver *lunp);
bool usbhmsdLUNIsProtected(USBHMassStorageLUNDriver *lunp);
+
+ /* global initializer */
+ void usbhmsdInit(void);
#ifdef __cplusplus
}
#endif
diff --git a/os/hal/include/usbh/dev/uvc.h b/os/hal/include/usbh/dev/uvc.h
new file mode 100644
index 0000000..ab12199
--- /dev/null
+++ b/os/hal/include/usbh/dev/uvc.h
@@ -0,0 +1,471 @@
+/*
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#ifndef USBH_INCLUDE_USBH_UVC_H_
+#define USBH_INCLUDE_USBH_UVC_H_
+
+#include "hal_usbh.h"
+
+#if HAL_USE_USBH && HAL_USBH_USE_UVC
+
+/* TODO:
+ *
+ *
+ */
+
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+#define USBHUVC_MAX_STATUS_PACKET_SZ 16
+
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+
+typedef enum {
+ UVC_CS_INTERFACE = 0x24,
+ UVC_CS_ENDPOINT = 0x25
+} usbh_uvc_cstype_t;
+
+typedef enum {
+ UVC_CC_VIDEO = 0x0e
+} usbh_uvc_cctype_t;
+
+typedef enum {
+ UVC_SC_UNKNOWN = 0x00,
+ UVC_SC_VIDEOCONTROL,
+ UVC_SC_VIDEOSTREAMING,
+ UVC_SC_VIDEO_INTERFACE_COLLECTION
+} usbh_uvc_sctype_t;
+
+typedef enum {
+ UVC_VC_UNDEF = 0x00,
+ UVC_VC_HEADER,
+ UVC_VC_INPUT_TERMINAL,
+ UVC_VC_OUTPUT_TERMINAL,
+ UVC_VC_SELECTOR_UNIT,
+ UVC_VC_PROCESSING_UNIT,
+ UVC_VC_EXTENSION_UNIT
+} usbh_uvc_vctype_t;
+
+typedef enum {
+ UVC_VS_UNDEF = 0x00,
+ UVC_VS_INPUT_HEADER,
+ UVC_VS_OUTPUT_HEADER,
+ UVC_VS_STILL_IMAGE_FRAME,
+ UVC_VS_FORMAT_UNCOMPRESSED,
+ UVC_VS_FRAME_UNCOMPRESSED,
+ UVC_VS_FORMAT_MJPEG,
+ UVC_VS_FRAME_MJPEG,
+ UVC_VS_RESERVED_0,
+ UVC_VS_RESERVED_1,
+ UVC_VS_FORMAT_MPEG2TS,
+ UVC_VS_RESERVED_2,
+ UVC_VS_FORMAT_DV,
+ UVC_VS_COLOR_FORMAT,
+ UVC_VS_RESERVED_3,
+ UVC_VS_RESERVED_4,
+ UVC_VS_FORMAT_FRAME_BASED,
+ UVC_VS_FRAME_FRAME_BASED,
+ UVC_VS_FORMAT_STREAM_BASED
+} usbh_uvc_vstype_t;
+
+typedef enum {
+ UVC_TT_VENDOR_SPECIFIC = 0x0100,
+ UVC_TT_STREAMING = 0x0101,
+ UVC_ITT_VENDOR_SPECIFIC = 0x0200,
+ UVC_ITT_CAMERA = 0x0201,
+ UVC_ITT_MEDIA_TRANSPORT_INPUT = 0x0202,
+ UVC_OTT_VENDOR_SPECIFIC = 0x0300,
+ UVC_OTT_DISPLAY = 0x0301,
+ UVC_OTT_MEDIA_TRANSPORT = 0x0302
+} usbh_uvc_tttype_t;
+
+typedef enum {
+ UVC_SET_CUR = 0x01,
+ UVC_GET_CUR = 0x81,
+ UVC_GET_MIN = 0x82,
+ UVC_GET_MAX = 0x83,
+ UVC_GET_RES = 0x84,
+ UVC_GET_LEN = 0x85,
+ UVC_GET_INFO = 0x86,
+ UVC_GET_DEF = 0x87
+} usbh_uvc_ctrlops_t;
+
+typedef enum {
+ UVC_CTRL_VC_CONTROL_UNDEFINED = 0x00,
+ UVC_CTRL_VC_VIDEO_POWER_MODE_CONTROL = 0x01,
+ UVC_CTRL_VC_REQUEST_ERROR_CODE_CONTROL = 0x02,
+} usbh_uvc_ctrl_vc_interface_controls_t;
+
+typedef enum {
+ UVC_CTRL_SU_CONTROL_UNDEFINED = 0x00,
+ UVC_CTRL_SU_INPUT_SELECT_CONTROL = 0x01,
+} usbh_uvc_ctrl_vc_selectorunit_controls_t;
+
+typedef enum {
+ UVC_CTRL_CT_CONTROL_UNDEFINED = 0x00,
+ UVC_CTRL_CT_SCANNING_MODE_CONTROL = 0x01,
+ UVC_CTRL_CT_AE_MODE_CONTROL = 0x02,
+ UVC_CTRL_CT_AE_PRIORITY_CONTROL = 0x03,
+ UVC_CTRL_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL = 0x04,
+ UVC_CTRL_CT_EXPOSURE_TIME_RELATIVE_CONTROL = 0x05,
+ UVC_CTRL_CT_FOCUS_ABSOLUTE_CONTROL = 0x06,
+ UVC_CTRL_CT_FOCUS_RELATIVE_CONTROL = 0x07,
+ UVC_CTRL_CT_FOCUS_AUTO_CONTROL = 0x08,
+ UVC_CTRL_CT_IRIS_ABSOLUTE_CONTROL = 0x09,
+ UVC_CTRL_CT_IRIS_RELATIVE_CONTROL = 0x0A,
+ UVC_CTRL_CT_ZOOM_ABSOLUTE_CONTROL = 0x0B,
+ UVC_CTRL_CT_ZOOM_RELATIVE_CONTROL = 0x0C,
+ UVC_CTRL_CT_PANTILT_ABSOLUTE_CONTROL = 0x0D,
+ UVC_CTRL_CT_PANTILT_RELATIVE_CONTROL = 0x0E,
+ UVC_CTRL_CT_ROLL_ABSOLUTE_CONTROL = 0x0F,
+ UVC_CTRL_CT_ROLL_RELATIVE_CONTROL = 0x10,
+ UVC_CTRL_CT_PRIVACY_CONTROL = 0x11
+} usbh_uvc_ctrl_vc_cameraterminal_controls_t;
+
+typedef enum {
+ UVC_CTRL_PU_CONTROL_UNDEFINED = 0x00,
+ UVC_CTRL_PU_BACKLIGHT_COMPENSATION_CONTROL = 0x01,
+ UVC_CTRL_PU_BRIGHTNESS_CONTROL = 0x02,
+ UVC_CTRL_PU_CONTRAST_CONTROL = 0x03,
+ UVC_CTRL_PU_GAIN_CONTROL = 0x04,
+ UVC_CTRL_PU_POWER_LINE_FREQUENCY_CONTROL = 0x05,
+ UVC_CTRL_PU_HUE_CONTROL = 0x06,
+ UVC_CTRL_PU_SATURATION_CONTROL = 0x07,
+ UVC_CTRL_PU_SHARPNESS_CONTROL = 0x08,
+ UVC_CTRL_PU_GAMMA_CONTROL = 0x09,
+ UVC_CTRL_PU_WHITE_BALANCE_TEMPERATURE_CONTROL = 0x0A,
+ UVC_CTRL_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL = 0x0B,
+ UVC_CTRL_PU_WHITE_BALANCE_COMPONENT_CONTROL = 0x0C,
+ UVC_CTRL_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL = 0x0D,
+ UVC_CTRL_PU_DIGITAL_MULTIPLIER_CONTROL = 0x0E,
+ UVC_CTRL_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL = 0x0F,
+ UVC_CTRL_PU_HUE_AUTO_CONTROL = 0x10,
+ UVC_CTRL_PU_ANALOG_VIDEO_STANDARD_CONTROL = 0x11,
+ UVC_CTRL_PU_ANALOG_LOCK_STATUS_CONTROL = 0x12,
+} usbh_uvc_ctrl_vc_processingunit_controls_t;
+
+typedef enum {
+ UVC_CTRL_VS_CONTROL_UNDEFINED = 0x00,
+ UVC_CTRL_VS_PROBE_CONTROL = 0x01,
+ UVC_CTRL_VS_COMMIT_CONTROL = 0x02,
+ UVC_CTRL_VS_STILL_PROBE_CONTROL = 0x03,
+ UVC_CTRL_VS_STILL_COMMIT_CONTROL = 0x04,
+ UVC_CTRL_VS_STILL_IMAGE_TRIGGER_CONTROL = 0x05,
+ UVC_CTRL_VS_STREAM_ERROR_CODE_CONTROL = 0x06,
+ UVC_CTRL_VS_GENERATE_KEY_FRAME_CONTROL = 0x07,
+ UVC_CTRL_VS_UPDATE_FRAME_SEGMENT_CONTROL = 0x08,
+ UVC_CTRL_VS_SYNCH_DELAY_CONTROL = 0x09
+} usbh_uvc_ctrl_vs_interface_controls_t;
+
+
+typedef struct {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFormatIndex;
+ uint8_t bNumFrameDescriptors;
+ uint8_t bmFlags;
+ uint8_t bDefaultFrameIndex;
+ uint8_t bAspectRatioX;
+ uint8_t bAspectRatioY;
+ uint8_t bmInterfaceFlags;
+ uint8_t bCopyProtect;
+} __attribute__((__packed__)) usbh_uvc_format_mjpeg_t;
+
+typedef struct {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFrameIndex;
+ uint8_t bmCapabilities;
+ uint16_t wWidth;
+ uint16_t wHeight;
+ uint32_t dwMinBitRate;
+ uint32_t dwMaxBitRate;
+ uint32_t dwMaxVideoFrameBufferSize;
+ uint32_t dwDefaultFrameInterval;
+ uint8_t bFrameIntervalType;
+ uint32_t dwFrameInterval[0];
+} __attribute__((__packed__)) usbh_uvc_frame_mjpeg_t;
+
+
+typedef struct {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFrameIndex;
+ uint8_t bmCapabilities;
+ uint16_t wWidth;
+ uint16_t wHeight;
+ uint32_t dwMinBitRate;
+ uint32_t dwMaxBitRate;
+ uint32_t dwMaxVideoFrameBufferSize;
+ uint32_t dwDefaultFrameInterval;
+ uint8_t bFrameIntervalType;
+ uint32_t dwFrameInterval[0];
+} __attribute__((__packed__)) usbh_uvc_frame_uncompressed_t;
+
+typedef struct {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bDescriptorSubType;
+ uint8_t bFormatIndex;
+ uint8_t bNumFrameDescriptors;
+ uint8_t guidFormat[16];
+ uint8_t bBitsPerPixel;
+ uint8_t bDefaultFrameIndex;
+ uint8_t bAspectRatioX;
+ uint8_t bAspectRatioY;
+ uint8_t bmInterfaceFlags;
+ uint8_t bCopyProtect;
+} __attribute__((__packed__)) usbh_uvc_format_uncompressed;
+
+typedef struct {
+ uint16_t bmHint;
+ uint8_t bFormatIndex;
+ uint8_t bFrameIndex;
+ uint32_t dwFrameInterval;
+ uint16_t wKeyFrameRate;
+ uint16_t wPFrameRate;
+ uint16_t wCompQuality;
+ uint16_t wCompWindowSize;
+ uint16_t wDelay;
+ uint32_t dwMaxVideoFrameSize;
+ uint32_t dwMaxPayloadTransferSize;
+// uint32_t dwClockFrequency;
+// uint8_t bmFramingInfo;
+// uint8_t bPreferedVersion;
+// uint8_t bMinVersion;
+// uint8_t bMaxVersion;
+} __attribute__((__packed__)) usbh_uvc_ctrl_vs_probecommit_data_t;
+
+
+
+/* D0: Frame ID.
+ * For frame-based formats, this bit toggles between 0 and 1 every time a new video frame begins.
+ * For stream-based formats, this bit toggles between 0 and 1 at the start of each new codec-specific
+ * segment. This behavior is required for frame-based payload formats (e.g., DV) and is optional
+ * for stream-based payload formats (e.g., MPEG-2 TS). For stream-based formats, support for this
+ * bit must be indicated via the bmFramingInfofield of the Video Probe and Commitcontrols
+ * (see section 4.3.1.1, “Video Probe and Commit Controls”).
+ *
+ * D1: End of Frame.
+ * This bit is set if the following payload data marks the end of the current video or still image
+ * frame (for framebased formats), or to indicate the end of a codec-specific segment
+ * (for stream-based formats). This behavior is optional for all payload formats.
+ * For stream-based formats, support for this bit must be indicated via the bmFramingInfofield
+ * of the Video Probe and CommitControls (see section 4.3.1.1, “Video Probe and Commit Controls”).
+ *
+ * D2: Presentation Time.
+ * This bit is set if the dwPresentationTimefield is being sent as part of the header.
+ *
+ * D3: Source Clock Reference
+ * This bit is set if the dwSourceClockfield is being sent as part of the header.
+ *
+ * D4: Reserved
+ *
+ * D5: Still Image
+ * This bit is set ifthe following data is part of a still image frame, and is only used for
+ * methods 2 and 3 of still image capture.
+ *
+ * D6: Error
+ * This bit is set ifthere was an error in the video or still image transmission
+ * for this payload. The StreamError Code control would reflect the cause of the error.
+ *
+ * D7: End of header
+ * This bit is set if this is the last header group in the packet, where the
+ * header group refers to this field and any optional fields identified by the bits in this
+ * field (Defined for future extension)
+*/
+
+#define UVC_HDR_EOH (1 << 7) /* End of header */
+#define UVC_HDR_ERR (1 << 6) /* Error */
+#define UVC_HDR_STILL (1 << 5) /* Still Image */
+#define UVC_HDR_SCR (1 << 3) /* Source Clock Reference */
+#define UVC_HDR_PT (1 << 2) /* Presentation Time */
+#define UVC_HDR_EOF (1 << 1) /* End of Frame */
+#define UVC_HDR_FID (1 << 0) /* Frame ID */
+
+
+
+typedef struct USBHUVCDriver USBHUVCDriver;
+
+#define USBHUVC_MESSAGETYPE_STATUS 1
+#define USBHUVC_MESSAGETYPE_DATA 2
+
+
+#define _usbhuvc_message_base_data \
+ uint16_t type; \
+ uint16_t length; \
+ systime_t timestamp;
+
+typedef struct {
+ _usbhuvc_message_base_data
+} usbhuvc_message_base_t;
+
+typedef struct {
+ _usbhuvc_message_base_data
+ USBH_DECLARE_STRUCT_MEMBER(uint8_t data[0]);
+} usbhuvc_message_data_t;
+
+typedef struct {
+ _usbhuvc_message_base_data
+ USBH_DECLARE_STRUCT_MEMBER(uint8_t data[USBHUVC_MAX_STATUS_PACKET_SZ]);
+} usbhuvc_message_status_t;
+
+
+typedef enum {
+ USBHUVC_STATE_UNINITIALIZED = 0, //must call usbhuvcObjectInit
+ USBHUVC_STATE_STOP = 1, //the device is disconnected
+ USBHUVC_STATE_ACTIVE = 2, //the device is connected
+ USBHUVC_STATE_READY = 3, //the device has negotiated the parameters
+ USBHUVC_STATE_STREAMING = 4, //the device is streaming data
+ USBHUVC_STATE_BUSY = 5 //the driver is busy performing some action
+} usbhuvc_state_t;
+
+
+struct USBHUVCDriver {
+ /* inherited from abstract class driver */
+ _usbh_base_classdriver_data
+
+ usbhuvc_state_t state;
+
+ usbh_ep_t ep_int;
+ usbh_ep_t ep_iso;
+
+ usbh_urb_t urb_iso;
+ usbh_urb_t urb_int;
+
+ if_iterator_t ivc;
+ if_iterator_t ivs;
+
+ USBH_DECLARE_STRUCT_MEMBER(usbh_uvc_ctrl_vs_probecommit_data_t pc);
+ USBH_DECLARE_STRUCT_MEMBER(usbh_uvc_ctrl_vs_probecommit_data_t pc_min);
+ USBH_DECLARE_STRUCT_MEMBER(usbh_uvc_ctrl_vs_probecommit_data_t pc_max);
+
+ mailbox_t mb;
+ msg_t mb_buff[HAL_USBHUVC_MAX_MAILBOX_SZ];
+
+ memory_pool_t mp_data;
+ void *mp_data_buffer;
+
+ memory_pool_t mp_status;
+ usbhuvc_message_status_t mp_status_buffer[HAL_USBHUVC_STATUS_PACKETS_COUNT];
+
+ mutex_t mtx;
+};
+
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+extern USBHUVCDriver USBHUVCD[HAL_USBHUVC_MAX_INSTANCES];
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void usbhuvcObjectInit(USBHUVCDriver *uvcd);
+
+ static inline usbhuvc_state_t usbhuvcGetState(USBHUVCDriver *uvcd) {
+ return uvcd->state;
+ }
+
+ bool usbhuvcVCRequest(USBHUVCDriver *uvcdp,
+ uint8_t bRequest, uint8_t entity, uint8_t control,
+ uint16_t wLength, uint8_t *data);
+ bool usbhuvcVSRequest(USBHUVCDriver *uvcdp,
+ uint8_t bRequest, uint8_t control,
+ uint16_t wLength, uint8_t *data);
+ bool usbhuvcFindVSDescriptor(USBHUVCDriver *uvcdp,
+ generic_iterator_t *ics,
+ uint8_t bDescriptorSubtype,
+ bool start);
+ uint32_t usbhuvcEstimateRequiredEPSize(USBHUVCDriver *uvcdp, const uint8_t *formatdesc,
+ const uint8_t *framedesc, uint32_t dwFrameInterval);
+
+#if USBH_DEBUG_ENABLE && USBHUVC_DEBUG_ENABLE_INFO
+ void usbhuvcPrintProbeCommit(const usbh_uvc_ctrl_vs_probecommit_data_t *pc);
+#else
+# define usbhuvcPrintProbeCommit(pc) do {} while(0)
+#endif
+ bool usbhuvcProbe(USBHUVCDriver *uvcdp);
+ bool usbhuvcCommit(USBHUVCDriver *uvcdp);
+ void usbhuvcResetPC(USBHUVCDriver *uvcdp);
+ static inline const usbh_uvc_ctrl_vs_probecommit_data_t *usbhuvcGetPCMin(USBHUVCDriver *uvcdp) {
+ return &uvcdp->pc_min;
+ }
+ static inline const usbh_uvc_ctrl_vs_probecommit_data_t *usbhuvcGetPCMax(USBHUVCDriver *uvcdp) {
+ return &uvcdp->pc_min;
+ }
+ static inline usbh_uvc_ctrl_vs_probecommit_data_t *usbhuvcGetPC(USBHUVCDriver *uvcdp) {
+ return &uvcdp->pc;
+ }
+
+ bool usbhuvcStreamStart(USBHUVCDriver *uvcdp, uint16_t min_ep_sz);
+ bool usbhuvcStreamStop(USBHUVCDriver *uvcdp);
+
+ static inline msg_t usbhuvcLockAndFetchS(USBHUVCDriver *uvcdp, msg_t *msg, systime_t timeout) {
+ chMtxLockS(&uvcdp->mtx);
+ msg_t ret = chMBFetchS(&uvcdp->mb, msg, timeout);
+ if (ret != MSG_OK)
+ chMtxUnlockS(&uvcdp->mtx);
+ return ret;
+ }
+ static inline msg_t usbhuvcLockAndFetch(USBHUVCDriver *uvcdp, msg_t *msg, systime_t timeout) {
+ osalSysLock();
+ msg_t ret = usbhuvcLockAndFetchS(uvcdp, msg, timeout);
+ osalSysUnlock();
+ return ret;
+ }
+ static inline void usbhuvcUnlock(USBHUVCDriver *uvcdp) {
+ chMtxUnlock(&uvcdp->mtx);
+ }
+ static inline void usbhuvcFreeDataMessage(USBHUVCDriver *uvcdp, usbhuvc_message_data_t *msg) {
+ chPoolFree(&uvcdp->mp_data, msg);
+ }
+ static inline void usbhuvcFreeStatusMessage(USBHUVCDriver *uvcdp, usbhuvc_message_status_t *msg) {
+ chPoolFree(&uvcdp->mp_status, msg);
+ }
+
+
+ /* global initializer */
+ void usbhuvcInit(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif /* USBH_INCLUDE_USBH_UVC_H_ */
diff --git a/os/hal/include/usbh/internal.h b/os/hal/include/usbh/internal.h
index baa477f..70d2f7a 100644
--- a/os/hal/include/usbh/internal.h
+++ b/os/hal/include/usbh/internal.h
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -29,9 +29,15 @@
#if HAL_USBH_USE_FTDI
extern const usbh_classdriverinfo_t usbhftdiClassDriverInfo;
#endif
+#if HAL_USBH_USE_AOA
+extern const usbh_classdriverinfo_t usbhaoaClassDriverInfo;
+#endif
#if HAL_USBH_USE_MSD
extern const usbh_classdriverinfo_t usbhmsdClassDriverInfo;
#endif
+#if HAL_USBH_USE_HID
+extern const usbh_classdriverinfo_t usbhhidClassDriverInfo;
+#endif
#if HAL_USBH_USE_UVC
extern const usbh_classdriverinfo_t usbhuvcClassDriverInfo;
#endif
@@ -49,29 +55,17 @@ bool _usbh_urb_abortI(usbh_urb_t *urb, usbh_urbstatus_t status);
void _usbh_urb_abort_and_waitS(usbh_urb_t *urb, usbh_urbstatus_t status);
-#define USBH_CLASSIN(type, req, value, index) \
- (USBH_REQTYPE_IN | type | USBH_REQTYPE_CLASS), \
- req, \
- value, \
- index
+#define USBH_REQTYPE_CLASSIN(type) \
+ (USBH_REQTYPE_DIR_IN | type | USBH_REQTYPE_TYPE_CLASS)
-#define USBH_CLASSOUT(type, req, value, index) \
- (USBH_REQTYPE_OUT | type | USBH_REQTYPE_CLASS), \
- req, \
- value, \
- index
+#define USBH_REQTYPE_CLASSOUT(type) \
+ (USBH_REQTYPE_DIR_OUT | type | USBH_REQTYPE_TYPE_CLASS)
-#define USBH_STANDARDIN(type, req, value, index) \
- (USBH_REQTYPE_IN | type | USBH_REQTYPE_STANDARD), \
- req, \
- value, \
- index
+#define USBH_REQTYPE_STANDARDIN(type) \
+ (USBH_REQTYPE_DIR_IN | type | USBH_REQTYPE_TYPE_STANDARD)
-#define USBH_STANDARDOUT(type, req, value, index) \
- (USBH_REQTYPE_OUT | type | USBH_REQTYPE_STANDARD), \
- req, \
- value, \
- index
+#define USBH_REQTYPE_STANDARDOUT(type) \
+ (USBH_REQTYPE_DIR_OUT | type | USBH_REQTYPE_TYPE_STANDARD)
#define USBH_PID_DATA0 0
@@ -82,19 +76,19 @@ void _usbh_urb_abort_and_waitS(usbh_urb_t *urb, usbh_urbstatus_t status);
/* GetBusState and SetHubDescriptor are optional, omitted */
-#define ClearHubFeature (((USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE) << 8) \
+#define ClearHubFeature (((USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_DEVICE) << 8) \
| USBH_REQ_CLEAR_FEATURE)
-#define SetHubFeature (((USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE) << 8) \
+#define SetHubFeature (((USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_DEVICE) << 8) \
| USBH_REQ_SET_FEATURE)
-#define ClearPortFeature (((USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER) << 8) \
+#define ClearPortFeature (((USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_OTHER) << 8) \
| USBH_REQ_CLEAR_FEATURE)
-#define SetPortFeature (((USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER) << 8) \
+#define SetPortFeature (((USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_OTHER) << 8) \
| USBH_REQ_SET_FEATURE)
-#define GetHubDescriptor (((USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE) << 8) \
+#define GetHubDescriptor (((USBH_REQTYPE_DIR_IN | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_DEVICE) << 8) \
| USBH_REQ_GET_DESCRIPTOR)
-#define GetHubStatus (((USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE) << 8) \
+#define GetHubStatus (((USBH_REQTYPE_DIR_IN | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_DEVICE) << 8) \
| USBH_REQ_GET_STATUS)
-#define GetPortStatus (((USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER) << 8) \
+#define GetPortStatus (((USBH_REQTYPE_DIR_IN | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_OTHER) << 8) \
| USBH_REQ_GET_STATUS)
diff --git a/os/hal/include/usbh/list.h b/os/hal/include/usbh/list.h
index 4eceacd..317e51b 100644
--- a/os/hal/include/usbh/list.h
+++ b/os/hal/include/usbh/list.h
@@ -7,11 +7,8 @@
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
-#define container_of(ptr, type, member) ((type *)(void *)((char *)(ptr) - offsetof(type, member)))
#ifndef container_of
-#define container_of(ptr, type, member) ({ \
- const typeof(((type *)0)->member) * __mptr = (ptr); \
- (type *)((char *)__mptr - offsetof(type, member)); })
+#define container_of(ptr, type, member) ((type *)(void *)((char *)(ptr) - offsetof(type, member)))
#endif
/*
diff --git a/os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h b/os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h
deleted file mode 100644
index 3322e51..0000000
--- a/os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h
+++ /dev/null
@@ -1,934 +0,0 @@
-/*
- ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/**
- * @file hal_stm32_otg.h
- * @brief STM32 OTG registers layout header.
- *
- * @addtogroup USB
- * @{
- */
-
-
-#ifndef HAL_STM32_OTG_H
-#define HAL_STM32_OTG_H
-
-/**
- * @brief Number of the implemented endpoints in OTG_FS.
- * @details This value does not include the endpoint 0 that is always present.
- */
-#define STM32_OTG1_ENDOPOINTS_NUMBER 3
-
-/**
- * @brief Number of the implemented endpoints in OTG_HS.
- * @details This value does not include the endpoint 0 that is always present.
- */
-#define STM32_OTG2_ENDOPOINTS_NUMBER 5
-
-/**
- * @brief OTG_FS FIFO memory size in words.
- */
-#define STM32_OTG1_FIFO_MEM_SIZE 320
-
-/**
- * @brief OTG_HS FIFO memory size in words.
- */
-#define STM32_OTG2_FIFO_MEM_SIZE 1024
-
-/**
- * @brief Host channel registers group.
- */
-typedef struct {
- volatile uint32_t HCCHAR; /**< @brief Host channel characteristics
- register. */
- volatile uint32_t resvd8;
- volatile uint32_t HCINT; /**< @brief Host channel interrupt register.*/
- volatile uint32_t HCINTMSK; /**< @brief Host channel interrupt mask
- register. */
- volatile uint32_t HCTSIZ; /**< @brief Host channel transfer size
- register. */
- volatile uint32_t resvd14;
- volatile uint32_t resvd18;
- volatile uint32_t resvd1c;
-} stm32_otg_host_chn_t;
-
-/**
- * @brief Device input endpoint registers group.
- */
-typedef struct {
- volatile uint32_t DIEPCTL; /**< @brief Device control IN endpoint
- control register. */
- volatile uint32_t resvd4;
- volatile uint32_t DIEPINT; /**< @brief Device IN endpoint interrupt
- register. */
- volatile uint32_t resvdC;
- volatile uint32_t DIEPTSIZ; /**< @brief Device IN endpoint transfer size
- register. */
- volatile uint32_t resvd14;
- volatile uint32_t DTXFSTS; /**< @brief Device IN endpoint transmit FIFO
- status register. */
- volatile uint32_t resvd1C;
-} stm32_otg_in_ep_t;
-
-/**
- * @brief Device output endpoint registers group.
- */
-typedef struct {
- volatile uint32_t DOEPCTL; /**< @brief Device control OUT endpoint
- control register. */
- volatile uint32_t resvd4;
- volatile uint32_t DOEPINT; /**< @brief Device OUT endpoint interrupt
- register. */
- volatile uint32_t resvdC;
- volatile uint32_t DOEPTSIZ; /**< @brief Device OUT endpoint transfer
- size register. */
- volatile uint32_t resvd14;
- volatile uint32_t resvd18;
- volatile uint32_t resvd1C;
-} stm32_otg_out_ep_t;
-
-/**
- * @brief USB registers memory map.
- */
-typedef struct {
- volatile uint32_t GOTGCTL; /**< @brief OTG control and status register.*/
- volatile uint32_t GOTGINT; /**< @brief OTG interrupt register. */
- volatile uint32_t GAHBCFG; /**< @brief AHB configuration register. */
- volatile uint32_t GUSBCFG; /**< @brief USB configuration register. */
- volatile uint32_t GRSTCTL; /**< @brief Reset register size. */
- volatile uint32_t GINTSTS; /**< @brief Interrupt register. */
- volatile uint32_t GINTMSK; /**< @brief Interrupt mask register. */
- volatile uint32_t GRXSTSR; /**< @brief Receive status debug read
- register. */
- volatile uint32_t GRXSTSP; /**< @brief Receive status read/pop
- register. */
- volatile uint32_t GRXFSIZ; /**< @brief Receive FIFO size register. */
- volatile uint32_t DIEPTXF0; /**< @brief Endpoint 0 transmit FIFO size
- register. */
- volatile uint32_t HNPTXSTS; /**< @brief Non-periodic transmit FIFO/queue
- status register. */
- volatile uint32_t resvd30;
- volatile uint32_t resvd34;
- volatile uint32_t GCCFG; /**< @brief General core configuration. */
- volatile uint32_t CID; /**< @brief Core ID register. */
- volatile uint32_t resvd58[48];
- volatile uint32_t HPTXFSIZ; /**< @brief Host periodic transmit FIFO size
- register. */
- volatile uint32_t DIEPTXF[15];/**< @brief Device IN endpoint transmit FIFO
- size registers. */
- volatile uint32_t resvd140[176];
- volatile uint32_t HCFG; /**< @brief Host configuration register. */
- volatile uint32_t HFIR; /**< @brief Host frame interval register. */
- volatile uint32_t HFNUM; /**< @brief Host frame number/frame time
- Remaining register. */
- volatile uint32_t resvd40C;
- volatile uint32_t HPTXSTS; /**< @brief Host periodic transmit FIFO/queue
- status register. */
- volatile uint32_t HAINT; /**< @brief Host all channels interrupt
- register. */
- volatile uint32_t HAINTMSK; /**< @brief Host all channels interrupt mask
- register. */
- volatile uint32_t resvd41C[9];
- volatile uint32_t HPRT; /**< @brief Host port control and status
- register. */
- volatile uint32_t resvd444[47];
- stm32_otg_host_chn_t hc[16]; /**< @brief Host channels array. */
- volatile uint32_t resvd700[64];
- volatile uint32_t DCFG; /**< @brief Device configuration register. */
- volatile uint32_t DCTL; /**< @brief Device control register. */
- volatile uint32_t DSTS; /**< @brief Device status register. */
- volatile uint32_t resvd80C;
- volatile uint32_t DIEPMSK; /**< @brief Device IN endpoint common
- interrupt mask register. */
- volatile uint32_t DOEPMSK; /**< @brief Device OUT endpoint common
- interrupt mask register. */
- volatile uint32_t DAINT; /**< @brief Device all endpoints interrupt
- register. */
- volatile uint32_t DAINTMSK; /**< @brief Device all endpoints interrupt
- mask register. */
- volatile uint32_t resvd820;
- volatile uint32_t resvd824;
- volatile uint32_t DVBUSDIS; /**< @brief Device VBUS discharge time
- register. */
- volatile uint32_t DVBUSPULSE; /**< @brief Device VBUS pulsing time
- register. */
- volatile uint32_t resvd830;
- volatile uint32_t DIEPEMPMSK; /**< @brief Device IN endpoint FIFO empty
- interrupt mask register. */
- volatile uint32_t resvd838;
- volatile uint32_t resvd83C;
- volatile uint32_t resvd840[16];
- volatile uint32_t resvd880[16];
- volatile uint32_t resvd8C0[16];
- stm32_otg_in_ep_t ie[16]; /**< @brief Input endpoints. */
- stm32_otg_out_ep_t oe[16]; /**< @brief Output endpoints. */
- volatile uint32_t resvdD00[64];
- volatile uint32_t PCGCCTL; /**< @brief Power and clock gating control
- register. */
- volatile uint32_t resvdE04[127];
- volatile uint32_t FIFO[16][1024];
-} stm32_otg_t;
-
-/**
- * @name GOTGCTL register bit definitions
- * @{
- */
-#define GOTGCTL_BSVLD (1U<<19) /**< B-Session Valid. */
-#define GOTGCTL_ASVLD (1U<<18) /**< A-Session Valid. */
-#define GOTGCTL_DBCT (1U<<17) /**< Long/Short debounce time. */
-#define GOTGCTL_CIDSTS (1U<<16) /**< Connector ID status. */
-#define GOTGCTL_EHEN (1U<<12)
-#define GOTGCTL_DHNPEN (1U<<11) /**< Device HNP enabled. */
-#define GOTGCTL_HSHNPEN (1U<<10) /**< Host Set HNP enable. */
-#define GOTGCTL_HNPRQ (1U<<9) /**< HNP request. */
-#define GOTGCTL_HNGSCS (1U<<8) /**< Host negotiation success. */
-#define GOTGCTL_BVALOVAL (1U<<7)
-#define GOTGCTL_BVALOEN (1U<<6)
-#define GOTGCTL_AVALOVAL (1U<<5)
-#define GOTGCTL_AVALOEN (1U<<4)
-#define GOTGCTL_VBVALOVAL (1U<<3)
-#define GOTGCTL_VBVALOEN (1U<<2)
-#define GOTGCTL_SRQ (1U<<1) /**< Session request. */
-#define GOTGCTL_SRQSCS (1U<<0) /**< Session request success. */
-/** @} */
-
-/**
- * @name GOTGINT register bit definitions
- * @{
- */
-#define GOTGINT_DBCDNE (1U<<19) /**< Debounce done. */
-#define GOTGINT_ADTOCHG (1U<<18) /**< A-Device timeout change. */
-#define GOTGINT_HNGDET (1U<<17) /**< Host negotiation detected. */
-#define GOTGINT_HNSSCHG (1U<<9) /**< Host negotiation success
- status change. */
-#define GOTGINT_SRSSCHG (1U<<8) /**< Session request success
- status change. */
-#define GOTGINT_SEDET (1U<<2) /**< Session end detected. */
-/** @} */
-
-/**
- * @name GAHBCFG register bit definitions
- * @{
- */
-#define GAHBCFG_PTXFELVL (1U<<8) /**< Periodic TxFIFO empty
- level. */
-#define GAHBCFG_TXFELVL (1U<<7) /**< Non-periodic TxFIFO empty
- level. */
-#define GAHBCFG_DMAEN (1U<<5) /**< DMA enable (HS only). */
-#define GAHBCFG_HBSTLEN_MASK (15U<<1) /**< Burst length/type mask (HS
- only). */
-#define GAHBCFG_HBSTLEN(n) ((n)<<1) /**< Burst length/type (HS
- only). */
-#define GAHBCFG_GINTMSK (1U<<0) /**< Global interrupt mask. */
-/** @} */
-
-/**
- * @name GUSBCFG register bit definitions
- * @{
- */
-#define GUSBCFG_CTXPKT (1U<<31) /**< Corrupt Tx packet. */
-#define GUSBCFG_FDMOD (1U<<30) /**< Force Device Mode. */
-#define GUSBCFG_FHMOD (1U<<29) /**< Force Host Mode. */
-#define GUSBCFG_TRDT_MASK (15U<<10) /**< USB Turnaround time field
- mask. */
-#define GUSBCFG_TRDT(n) ((n)<<10) /**< USB Turnaround time field
- value. */
-#define GUSBCFG_HNPCAP (1U<<9) /**< HNP-Capable. */
-#define GUSBCFG_SRPCAP (1U<<8) /**< SRP-Capable. */
-#define GUSBCFG_PHYSEL (1U<<6) /**< USB 2.0 High-Speed PHY or
- USB 1.1 Full-Speed serial
- transceiver Select. */
-#define GUSBCFG_TOCAL_MASK (7U<<0) /**< HS/FS timeout calibration
- field mask. */
-#define GUSBCFG_TOCAL(n) ((n)<<0) /**< HS/FS timeout calibration
- field value. */
-/** @} */
-
-/**
- * @name GRSTCTL register bit definitions
- * @{
- */
-#define GRSTCTL_AHBIDL (1U<<31) /**< AHB Master Idle. */
-#define GRSTCTL_TXFNUM_MASK (31U<<6) /**< TxFIFO number field mask. */
-#define GRSTCTL_TXFNUM(n) ((n)<<6) /**< TxFIFO number field value. */
-#define GRSTCTL_TXFFLSH (1U<<5) /**< TxFIFO flush. */
-#define GRSTCTL_RXFFLSH (1U<<4) /**< RxFIFO flush. */
-#define GRSTCTL_FCRST (1U<<2) /**< Host frame counter reset. */
-#define GRSTCTL_HSRST (1U<<1) /**< HClk soft reset. */
-#define GRSTCTL_CSRST (1U<<0) /**< Core soft reset. */
-/** @} */
-
-/**
- * @name GINTSTS register bit definitions
- * @{
- */
-#define GINTSTS_WKUPINT (1U<<31) /**< Resume/Remote wakeup
- detected interrupt. */
-#define GINTSTS_SRQINT (1U<<30) /**< Session request/New session
- detected interrupt. */
-#define GINTSTS_DISCINT (1U<<29) /**< Disconnect detected
- interrupt. */
-#define GINTSTS_CIDSCHG (1U<<28) /**< Connector ID status change.*/
-#define GINTSTS_PTXFE (1U<<26) /**< Periodic TxFIFO empty. */
-#define GINTSTS_HCINT (1U<<25) /**< Host channels interrupt. */
-#define GINTSTS_HPRTINT (1U<<24) /**< Host port interrupt. */
-#define GINTSTS_IPXFR (1U<<21) /**< Incomplete periodic
- transfer. */
-#define GINTSTS_IISOOXFR (1U<<21) /**< Incomplete isochronous OUT
- transfer. */
-#define GINTSTS_IISOIXFR (1U<<20) /**< Incomplete isochronous IN
- transfer. */
-#define GINTSTS_OEPINT (1U<<19) /**< OUT endpoints interrupt. */
-#define GINTSTS_IEPINT (1U<<18) /**< IN endpoints interrupt. */
-#define GINTSTS_EOPF (1U<<15) /**< End of periodic frame
- interrupt. */
-#define GINTSTS_ISOODRP (1U<<14) /**< Isochronous OUT packet
- dropped interrupt. */
-#define GINTSTS_ENUMDNE (1U<<13) /**< Enumeration done. */
-#define GINTSTS_USBRST (1U<<12) /**< USB reset. */
-#define GINTSTS_USBSUSP (1U<<11) /**< USB suspend. */
-#define GINTSTS_ESUSP (1U<<10) /**< Early suspend. */
-#define GINTSTS_GONAKEFF (1U<<7) /**< Global OUT NAK effective. */
-#define GINTSTS_GINAKEFF (1U<<6) /**< Global IN non-periodic NAK
- effective. */
-#define GINTSTS_NPTXFE (1U<<5) /**< Non-periodic TxFIFO empty. */
-#define GINTSTS_RXFLVL (1U<<4) /**< RxFIFO non-empty. */
-#define GINTSTS_SOF (1U<<3) /**< Start of frame. */
-#define GINTSTS_OTGINT (1U<<2) /**< OTG interrupt. */
-#define GINTSTS_MMIS (1U<<1) /**< Mode Mismatch interrupt. */
-#define GINTSTS_CMOD (1U<<0) /**< Current mode of operation. */
-/** @} */
-
-/**
- * @name GINTMSK register bit definitions
- * @{
- */
-#define GINTMSK_WKUM (1U<<31) /**< Resume/remote wakeup
- detected interrupt mask. */
-#define GINTMSK_SRQM (1U<<30) /**< Session request/New session
- detected interrupt mask. */
-#define GINTMSK_DISCM (1U<<29) /**< Disconnect detected
- interrupt mask. */
-#define GINTMSK_CIDSCHGM (1U<<28) /**< Connector ID status change
- mask. */
-#define GINTMSK_PTXFEM (1U<<26) /**< Periodic TxFIFO empty mask.*/
-#define GINTMSK_HCM (1U<<25) /**< Host channels interrupt
- mask. */
-#define GINTMSK_HPRTM (1U<<24) /**< Host port interrupt mask. */
-#define GINTMSK_IPXFRM (1U<<21) /**< Incomplete periodic
- transfer mask. */
-#define GINTMSK_IISOOXFRM (1U<<21) /**< Incomplete isochronous OUT
- transfer mask. */
-#define GINTMSK_IISOIXFRM (1U<<20) /**< Incomplete isochronous IN
- transfer mask. */
-#define GINTMSK_OEPM (1U<<19) /**< OUT endpoints interrupt
- mask. */
-#define GINTMSK_IEPM (1U<<18) /**< IN endpoints interrupt
- mask. */
-#define GINTMSK_EOPFM (1U<<15) /**< End of periodic frame
- interrupt mask. */
-#define GINTMSK_ISOODRPM (1U<<14) /**< Isochronous OUT packet
- dropped interrupt mask. */
-#define GINTMSK_ENUMDNEM (1U<<13) /**< Enumeration done mask. */
-#define GINTMSK_USBRSTM (1U<<12) /**< USB reset mask. */
-#define GINTMSK_USBSUSPM (1U<<11) /**< USB suspend mask. */
-#define GINTMSK_ESUSPM (1U<<10) /**< Early suspend mask. */
-#define GINTMSK_GONAKEFFM (1U<<7) /**< Global OUT NAK effective
- mask. */
-#define GINTMSK_GINAKEFFM (1U<<6) /**< Global non-periodic IN NAK
- effective mask. */
-#define GINTMSK_NPTXFEM (1U<<5) /**< Non-periodic TxFIFO empty
- mask. */
-#define GINTMSK_RXFLVLM (1U<<4) /**< Receive FIFO non-empty
- mask. */
-#define GINTMSK_SOFM (1U<<3) /**< Start of (micro)frame mask.*/
-#define GINTMSK_OTGM (1U<<2) /**< OTG interrupt mask. */
-#define GINTMSK_MMISM (1U<<1) /**< Mode Mismatch interrupt
- mask. */
-/** @} */
-
-/**
- * @name GRXSTSR register bit definitions
- * @{
- */
-#define GRXSTSR_PKTSTS_MASK (15U<<17) /**< Packet status mask. */
-#define GRXSTSR_PKTSTS(n) ((n)<<17) /**< Packet status value. */
-#define GRXSTSR_OUT_GLOBAL_NAK GRXSTSR_PKTSTS(1)
-#define GRXSTSR_OUT_DATA GRXSTSR_PKTSTS(2)
-#define GRXSTSR_OUT_COMP GRXSTSR_PKTSTS(3)
-#define GRXSTSR_SETUP_COMP GRXSTSR_PKTSTS(4)
-#define GRXSTSR_SETUP_DATA GRXSTSR_PKTSTS(6)
-#define GRXSTSR_DPID_MASK (3U<<15) /**< Data PID mask. */
-#define GRXSTSR_DPID(n) ((n)<<15) /**< Data PID value. */
-#define GRXSTSR_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */
-#define GRXSTSR_BCNT(n) ((n)<<4) /**< Byte count value. */
-#define GRXSTSR_CHNUM_MASK (15U<<0) /**< Channel number mask. */
-#define GRXSTSR_CHNUM(n) ((n)<<0) /**< Channel number value. */
-#define GRXSTSR_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */
-#define GRXSTSR_EPNUM(n) ((n)<<0) /**< Endpoint number value. */
-/** @} */
-
-/**
- * @name GRXSTSP register bit definitions
- * @{
- */
-#define GRXSTSP_PKTSTS_MASK (15<<17) /**< Packet status mask. */
-#define GRXSTSP_PKTSTS(n) ((n)<<17) /**< Packet status value. */
-#define GRXSTSP_OUT_GLOBAL_NAK GRXSTSP_PKTSTS(1)
-#define GRXSTSP_OUT_DATA GRXSTSP_PKTSTS(2)
-#define GRXSTSP_OUT_COMP GRXSTSP_PKTSTS(3)
-#define GRXSTSP_SETUP_COMP GRXSTSP_PKTSTS(4)
-#define GRXSTSP_SETUP_DATA GRXSTSP_PKTSTS(6)
-#define GRXSTSP_DPID_MASK (3U<<15) /**< Data PID mask. */
-#define GRXSTSP_DPID(n) ((n)<<15) /**< Data PID value. */
-#define GRXSTSP_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */
-#define GRXSTSP_BCNT_OFF 4 /**< Byte count offset. */
-#define GRXSTSP_BCNT(n) ((n)<<4) /**< Byte count value. */
-#define GRXSTSP_CHNUM_MASK (15U<<0) /**< Channel number mask. */
-#define GRXSTSP_CHNUM(n) ((n)<<0) /**< Channel number value. */
-#define GRXSTSP_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */
-#define GRXSTSP_EPNUM_OFF 0 /**< Endpoint number offset. */
-#define GRXSTSP_EPNUM(n) ((n)<<0) /**< Endpoint number value. */
-/** @} */
-
-/**
- * @name GRXFSIZ register bit definitions
- * @{
- */
-#define GRXFSIZ_RXFD_MASK (0xFFFF<<0) /**< RxFIFO depth mask. */
-#define GRXFSIZ_RXFD(n) ((n)<<0) /**< RxFIFO depth value. */
-/** @} */
-
-/**
- * @name DIEPTXFx register bit definitions
- * @{
- */
-#define DIEPTXF_INEPTXFD_MASK (0xFFFFU<<16)/**< IN endpoint TxFIFO depth
- mask. */
-#define DIEPTXF_INEPTXFD(n) ((n)<<16) /**< IN endpoint TxFIFO depth
- value. */
-#define DIEPTXF_INEPTXSA_MASK (0xFFFF<<0) /**< IN endpoint FIFOx transmit
- RAM start address mask. */
-#define DIEPTXF_INEPTXSA(n) ((n)<<0) /**< IN endpoint FIFOx transmit
- RAM start address value. */
-/** @} */
-
-/**
- * @name GCCFG register bit definitions
- * @{
- */
-/* Definitions for stepping 1.*/
-#define GCCFG_NOVBUSSENS (1U<<21) /**< VBUS sensing disable. */
-#define GCCFG_SOFOUTEN (1U<<20) /**< SOF output enable. */
-#define GCCFG_VBUSBSEN (1U<<19) /**< Enable the VBUS sensing "B"
- device. */
-#define GCCFG_VBUSASEN (1U<<18) /**< Enable the VBUS sensing "A"
- device. */
-
-/* Definitions for stepping 2.*/
-#define GCCFG_VBDEN (1U<<21) /**< VBUS sensing enable. */
-#define GCCFG_PWRDWN (1U<<16) /**< Power down. */
-/** @} */
-
-/**
- * @name HPTXFSIZ register bit definitions
- * @{
- */
-#define HPTXFSIZ_PTXFD_MASK (0xFFFFU<<16)/**< Host periodic TxFIFO
- depth mask. */
-#define HPTXFSIZ_PTXFD(n) ((n)<<16) /**< Host periodic TxFIFO
- depth value. */
-#define HPTXFSIZ_PTXSA_MASK (0xFFFFU<<0)/**< Host periodic TxFIFO
- Start address mask. */
-#define HPTXFSIZ_PTXSA(n) ((n)<<0) /**< Host periodic TxFIFO
- start address value. */
-/** @} */
-
-/**
- * @name HCFG register bit definitions
- * @{
- */
-#define HCFG_FSLSS (1U<<2) /**< FS- and LS-only support. */
-#define HCFG_FSLSPCS_MASK (3U<<0) /**< FS/LS PHY clock select
- mask. */
-#define HCFG_FSLSPCS_48 (1U<<0) /**< PHY clock is running at
- 48 MHz. */
-#define HCFG_FSLSPCS_6 (2U<<0) /**< PHY clock is running at
- 6 MHz. */
-/** @} */
-
-/**
- * @name HFIR register bit definitions
- * @{
- */
-#define HFIR_FRIVL_MASK (0xFFFFU<<0)/**< Frame interval mask. */
-#define HFIR_FRIVL(n) ((n)<<0) /**< Frame interval value. */
-/** @} */
-
-/**
- * @name HFNUM register bit definitions
- * @{
- */
-#define HFNUM_FTREM_MASK (0xFFFFU<<16)/**< Frame time Remaining mask.*/
-#define HFNUM_FTREM(n) ((n)<<16) /**< Frame time Remaining value.*/
-#define HFNUM_FRNUM_MASK (0xFFFFU<<0)/**< Frame number mask. */
-#define HFNUM_FRNUM(n) ((n)<<0) /**< Frame number value. */
-/** @} */
-
-/**
- * @name HPTXSTS register bit definitions
- * @{
- */
-#define HPTXSTS_PTXQTOP_MASK (0xFFU<<24) /**< Top of the periodic
- transmit request queue
- mask. */
-#define HPTXSTS_PTXQTOP(n) ((n)<<24) /**< Top of the periodic
- transmit request queue
- value. */
-#define HPTXSTS_PTXQSAV_MASK (0xFF<<16) /**< Periodic transmit request
- queue Space Available
- mask. */
-#define HPTXSTS_PTXQSAV(n) ((n)<<16) /**< Periodic transmit request
- queue Space Available
- value. */
-#define HPTXSTS_PTXFSAVL_MASK (0xFFFF<<0) /**< Periodic transmit Data
- FIFO Space Available
- mask. */
-#define HPTXSTS_PTXFSAVL(n) ((n)<<0) /**< Periodic transmit Data
- FIFO Space Available
- value. */
-/** @} */
-
-/**
- * @name HAINT register bit definitions
- * @{
- */
-#define HAINT_HAINT_MASK (0xFFFFU<<0)/**< Channel interrupts mask. */
-#define HAINT_HAINT(n) ((n)<<0) /**< Channel interrupts value. */
-/** @} */
-
-/**
- * @name HAINTMSK register bit definitions
- * @{
- */
-#define HAINTMSK_HAINTM_MASK (0xFFFFU<<0)/**< Channel interrupt mask
- mask. */
-#define HAINTMSK_HAINTM(n) ((n)<<0) /**< Channel interrupt mask
- value. */
-/** @} */
-
-/**
- * @name HPRT register bit definitions
- * @{
- */
-#define HPRT_PSPD_MASK (3U<<17) /**< Port speed mask. */
-#define HPRT_PSPD_FS (1U<<17) /**< Full speed value. */
-#define HPRT_PSPD_LS (2U<<17) /**< Low speed value. */
-#define HPRT_PTCTL_MASK (15<<13) /**< Port Test control mask. */
-#define HPRT_PTCTL(n) ((n)<<13) /**< Port Test control value. */
-#define HPRT_PPWR (1U<<12) /**< Port power. */
-#define HPRT_PLSTS_MASK (3U<<11) /**< Port Line status mask. */
-#define HPRT_PLSTS_DM (1U<<11) /**< Logic level of D-. */
-#define HPRT_PLSTS_DP (1U<<10) /**< Logic level of D+. */
-#define HPRT_PRST (1U<<8) /**< Port reset. */
-#define HPRT_PSUSP (1U<<7) /**< Port suspend. */
-#define HPRT_PRES (1U<<6) /**< Port Resume. */
-#define HPRT_POCCHNG (1U<<5) /**< Port overcurrent change. */
-#define HPRT_POCA (1U<<4) /**< Port overcurrent active. */
-#define HPRT_PENCHNG (1U<<3) /**< Port enable/disable change.*/
-#define HPRT_PENA (1U<<2) /**< Port enable. */
-#define HPRT_PCDET (1U<<1) /**< Port Connect detected. */
-#define HPRT_PCSTS (1U<<0) /**< Port connect status. */
-/** @} */
-
-/**
- * @name HCCHAR register bit definitions
- * @{
- */
-#define HCCHAR_CHENA (1U<<31) /**< Channel enable. */
-#define HCCHAR_CHDIS (1U<<30) /**< Channel Disable. */
-#define HCCHAR_ODDFRM (1U<<29) /**< Odd frame. */
-#define HCCHAR_DAD_MASK (0x7FU<<22) /**< Device Address mask. */
-#define HCCHAR_DAD(n) ((n)<<22) /**< Device Address value. */
-#define HCCHAR_MCNT_MASK (3U<<20) /**< Multicount mask. */
-#define HCCHAR_MCNT(n) ((n)<<20) /**< Multicount value. */
-#define HCCHAR_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */
-#define HCCHAR_EPTYP(n) ((n)<<18) /**< Endpoint type value. */
-#define HCCHAR_EPTYP_CTL (0U<<18) /**< Control endpoint value. */
-#define HCCHAR_EPTYP_ISO (1U<<18) /**< Isochronous endpoint value.*/
-#define HCCHAR_EPTYP_BULK (2U<<18) /**< Bulk endpoint value. */
-#define HCCHAR_EPTYP_INTR (3U<<18) /**< Interrupt endpoint value. */
-#define HCCHAR_LSDEV (1U<<17) /**< Low-Speed device. */
-#define HCCHAR_EPDIR (1U<<15) /**< Endpoint direction. */
-#define HCCHAR_EPNUM_MASK (15U<<11) /**< Endpoint number mask. */
-#define HCCHAR_EPNUM(n) ((n)<<11) /**< Endpoint number value. */
-#define HCCHAR_MPS_MASK (0x7FFU<<0) /**< Maximum packet size mask. */
-#define HCCHAR_MPS(n) ((n)<<0) /**< Maximum packet size value. */
-/** @} */
-
-/**
- * @name HCINT register bit definitions
- * @{
- */
-#define HCINT_DTERR (1U<<10) /**< Data toggle error. */
-#define HCINT_FRMOR (1U<<9) /**< Frame overrun. */
-#define HCINT_BBERR (1U<<8) /**< Babble error. */
-#define HCINT_TRERR (1U<<7) /**< Transaction Error. */
-#define HCINT_ACK (1U<<5) /**< ACK response
- received/transmitted
- interrupt. */
-#define HCINT_NAK (1U<<4) /**< NAK response received
- interrupt. */
-#define HCINT_STALL (1U<<3) /**< STALL response received
- interrupt. */
-#define HCINT_AHBERR (1U<<2) /**< AHB error interrupt. */
-#define HCINT_CHH (1U<<1) /**< Channel halted. */
-#define HCINT_XFRC (1U<<0) /**< Transfer completed. */
-/** @} */
-
-/**
- * @name HCINTMSK register bit definitions
- * @{
- */
-#define HCINTMSK_DTERRM (1U<<10) /**< Data toggle error mask. */
-#define HCINTMSK_FRMORM (1U<<9) /**< Frame overrun mask. */
-#define HCINTMSK_BBERRM (1U<<8) /**< Babble error mask. */
-#define HCINTMSK_TRERRM (1U<<7) /**< Transaction error mask. */
-#define HCINTMSK_NYET (1U<<6) /**< NYET response received
- interrupt mask. */
-#define HCINTMSK_ACKM (1U<<5) /**< ACK Response
- received/transmitted
- interrupt mask. */
-#define HCINTMSK_NAKM (1U<<4) /**< NAK response received
- interrupt mask. */
-#define HCINTMSK_STALLM (1U<<3) /**< STALL response received
- interrupt mask. */
-#define HCINTMSK_AHBERRM (1U<<2) /**< AHB error interrupt mask. */
-#define HCINTMSK_CHHM (1U<<1) /**< Channel halted mask. */
-#define HCINTMSK_XFRCM (1U<<0) /**< Transfer completed mask. */
-/** @} */
-
-/**
- * @name HCTSIZ register bit definitions
- * @{
- */
-#define HCTSIZ_DPID_MASK (3U<<29) /**< PID mask. */
-#define HCTSIZ_DPID_DATA0 (0U<<29) /**< DATA0. */
-#define HCTSIZ_DPID_DATA2 (1U<<29) /**< DATA2. */
-#define HCTSIZ_DPID_DATA1 (2U<<29) /**< DATA1. */
-#define HCTSIZ_DPID_MDATA (3U<<29) /**< MDATA. */
-#define HCTSIZ_DPID_SETUP (3U<<29) /**< SETUP. */
-#define HCTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */
-#define HCTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
-#define HCTSIZ_XFRSIZ_MASK (0x7FFFF<<0)/**< Transfer size mask. */
-#define HCTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
-/** @} */
-
-/**
- * @name DCFG register bit definitions
- * @{
- */
-#define DCFG_PFIVL_MASK (3U<<11) /**< Periodic frame interval
- mask. */
-#define DCFG_PFIVL(n) ((n)<<11) /**< Periodic frame interval
- value. */
-#define DCFG_DAD_MASK (0x7FU<<4) /**< Device address mask. */
-#define DCFG_DAD(n) ((n)<<4) /**< Device address value. */
-#define DCFG_NZLSOHSK (1U<<2) /**< Non-Zero-Length status
- OUT handshake. */
-#define DCFG_DSPD_MASK (3U<<0) /**< Device speed mask. */
-#define DCFG_DSPD_HS (0U<<0) /**< High speed (USB 2.0). */
-#define DCFG_DSPD_HS_FS (1U<<0) /**< High speed (USB 2.0) in FS
- mode. */
-#define DCFG_DSPD_FS11 (3U<<0) /**< Full speed (USB 1.1
- transceiver clock is 48
- MHz). */
-/** @} */
-
-/**
- * @name DCTL register bit definitions
- * @{
- */
-#define DCTL_POPRGDNE (1U<<11) /**< Power-on programming done. */
-#define DCTL_CGONAK (1U<<10) /**< Clear global OUT NAK. */
-#define DCTL_SGONAK (1U<<9) /**< Set global OUT NAK. */
-#define DCTL_CGINAK (1U<<8) /**< Clear global non-periodic
- IN NAK. */
-#define DCTL_SGINAK (1U<<7) /**< Set global non-periodic
- IN NAK. */
-#define DCTL_TCTL_MASK (7U<<4) /**< Test control mask. */
-#define DCTL_TCTL(n) ((n)<<4 /**< Test control value. */
-#define DCTL_GONSTS (1U<<3) /**< Global OUT NAK status. */
-#define DCTL_GINSTS (1U<<2) /**< Global non-periodic IN
- NAK status. */
-#define DCTL_SDIS (1U<<1) /**< Soft disconnect. */
-#define DCTL_RWUSIG (1U<<0) /**< Remote wakeup signaling. */
-/** @} */
-
-/**
- * @name DSTS register bit definitions
- * @{
- */
-#define DSTS_FNSOF_MASK (0x3FFU<<8) /**< Frame number of the received
- SOF mask. */
-#define DSTS_FNSOF(n) ((n)<<8) /**< Frame number of the received
- SOF value. */
-#define DSTS_FNSOF_ODD (1U<<8) /**< Frame parity of the received
- SOF value. */
-#define DSTS_EERR (1U<<3) /**< Erratic error. */
-#define DSTS_ENUMSPD_MASK (3U<<1) /**< Enumerated speed mask. */
-#define DSTS_ENUMSPD_FS_48 (3U<<1) /**< Full speed (PHY clock is
- running at 48 MHz). */
-#define DSTS_ENUMSPD_HS_480 (0U<<1) /**< High speed. */
-#define DSTS_SUSPSTS (1U<<0) /**< Suspend status. */
-/** @} */
-
-/**
- * @name DIEPMSK register bit definitions
- * @{
- */
-#define DIEPMSK_TXFEM (1U<<6) /**< Transmit FIFO empty mask. */
-#define DIEPMSK_INEPNEM (1U<<6) /**< IN endpoint NAK effective
- mask. */
-#define DIEPMSK_ITTXFEMSK (1U<<4) /**< IN token received when
- TxFIFO empty mask. */
-#define DIEPMSK_TOCM (1U<<3) /**< Timeout condition mask. */
-#define DIEPMSK_EPDM (1U<<1) /**< Endpoint disabled
- interrupt mask. */
-#define DIEPMSK_XFRCM (1U<<0) /**< Transfer completed
- interrupt mask. */
-/** @} */
-
-/**
- * @name DOEPMSK register bit definitions
- * @{
- */
-#define DOEPMSK_OTEPDM (1U<<4) /**< OUT token received when
- endpoint disabled mask. */
-#define DOEPMSK_STUPM (1U<<3) /**< SETUP phase done mask. */
-#define DOEPMSK_EPDM (1U<<1) /**< Endpoint disabled
- interrupt mask. */
-#define DOEPMSK_XFRCM (1U<<0) /**< Transfer completed
- interrupt mask. */
-/** @} */
-
-/**
- * @name DAINT register bit definitions
- * @{
- */
-#define DAINT_OEPINT_MASK (0xFFFFU<<16)/**< OUT endpoint interrupt
- bits mask. */
-#define DAINT_OEPINT(n) ((n)<<16) /**< OUT endpoint interrupt
- bits value. */
-#define DAINT_IEPINT_MASK (0xFFFFU<<0)/**< IN endpoint interrupt
- bits mask. */
-#define DAINT_IEPINT(n) ((n)<<0) /**< IN endpoint interrupt
- bits value. */
-/** @} */
-
-/**
- * @name DAINTMSK register bit definitions
- * @{
- */
-#define DAINTMSK_OEPM_MASK (0xFFFFU<<16)/**< OUT EP interrupt mask
- bits mask. */
-#define DAINTMSK_OEPM(n) (1U<<(16+(n)))/**< OUT EP interrupt mask
- bits value. */
-#define DAINTMSK_IEPM_MASK (0xFFFFU<<0)/**< IN EP interrupt mask
- bits mask. */
-#define DAINTMSK_IEPM(n) (1U<<(n)) /**< IN EP interrupt mask
- bits value. */
-/** @} */
-
-/**
- * @name DVBUSDIS register bit definitions
- * @{
- */
-#define DVBUSDIS_VBUSDT_MASK (0xFFFFU<<0)/**< Device VBUS discharge
- time mask. */
-#define DVBUSDIS_VBUSDT(n) ((n)<<0) /**< Device VBUS discharge
- time value. */
-/** @} */
-
-/**
- * @name DVBUSPULSE register bit definitions
- * @{
- */
-#define DVBUSPULSE_DVBUSP_MASK (0xFFFU<<0) /**< Device VBUSpulsing time
- mask. */
-#define DVBUSPULSE_DVBUSP(n) ((n)<<0) /**< Device VBUS pulsing time
- value. */
-/** @} */
-
-/**
- * @name DIEPEMPMSK register bit definitions
- * @{
- */
-#define DIEPEMPMSK_INEPTXFEM(n) (1U<<(n)) /**< IN EP Tx FIFO empty
- interrupt mask bit. */
-/** @} */
-
-/**
- * @name DIEPCTL register bit definitions
- * @{
- */
-#define DIEPCTL_EPENA (1U<<31) /**< Endpoint enable. */
-#define DIEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */
-#define DIEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */
-#define DIEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */
-#define DIEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */
-#define DIEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */
-#define DIEPCTL_SNAK (1U<<27) /**< Set NAK. */
-#define DIEPCTL_CNAK (1U<<26) /**< Clear NAK. */
-#define DIEPCTL_TXFNUM_MASK (15U<<22) /**< TxFIFO number mask. */
-#define DIEPCTL_TXFNUM(n) ((n)<<22) /**< TxFIFO number value. */
-#define DIEPCTL_STALL (1U<<21) /**< STALL handshake. */
-#define DIEPCTL_SNPM (1U<<20) /**< Snoop mode. */
-#define DIEPCTL_EPTYP_MASK (3<<18) /**< Endpoint type mask. */
-#define DIEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */
-#define DIEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */
-#define DIEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */
-#define DIEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */
-#define DIEPCTL_NAKSTS (1U<<17) /**< NAK status. */
-#define DIEPCTL_EONUM (1U<<16) /**< Even/odd frame. */
-#define DIEPCTL_DPID (1U<<16) /**< Endpoint data PID. */
-#define DIEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */
-#define DIEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */
-#define DIEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */
-/** @} */
-
-/**
- * @name DIEPINT register bit definitions
- * @{
- */
-#define DIEPINT_TXFE (1U<<7) /**< Transmit FIFO empty. */
-#define DIEPINT_INEPNE (1U<<6) /**< IN endpoint NAK effective. */
-#define DIEPINT_ITTXFE (1U<<4) /**< IN Token received when
- TxFIFO is empty. */
-#define DIEPINT_TOC (1U<<3) /**< Timeout condition. */
-#define DIEPINT_EPDISD (1U<<1) /**< Endpoint disabled
- interrupt. */
-#define DIEPINT_XFRC (1U<<0) /**< Transfer completed. */
-/** @} */
-
-/**
- * @name DIEPTSIZ register bit definitions
- * @{
- */
-#define DIEPTSIZ_MCNT_MASK (3U<<29) /**< Multi count mask. */
-#define DIEPTSIZ_MCNT(n) ((n)<<29) /**< Multi count value. */
-#define DIEPTSIZ_PKTCNT_MASK (0x3FF<<19) /**< Packet count mask. */
-#define DIEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
-#define DIEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */
-#define DIEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
-/** @} */
-
-/**
- * @name DTXFSTS register bit definitions.
- * @{
- */
-#define DTXFSTS_INEPTFSAV_MASK (0xFFFF<<0) /**< IN endpoint TxFIFO space
- available. */
-/** @} */
-
-/**
- * @name DOEPCTL register bit definitions.
- * @{
- */
-#define DOEPCTL_EPENA (1U<<31) /**< Endpoint enable. */
-#define DOEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */
-#define DOEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */
-#define DOEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */
-#define DOEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */
-#define DOEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */
-#define DOEPCTL_SNAK (1U<<27) /**< Set NAK. */
-#define DOEPCTL_CNAK (1U<<26) /**< Clear NAK. */
-#define DOEPCTL_STALL (1U<<21) /**< STALL handshake. */
-#define DOEPCTL_SNPM (1U<<20) /**< Snoop mode. */
-#define DOEPCTL_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */
-#define DOEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */
-#define DOEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */
-#define DOEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */
-#define DOEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */
-#define DOEPCTL_NAKSTS (1U<<17) /**< NAK status. */
-#define DOEPCTL_EONUM (1U<<16) /**< Even/odd frame. */
-#define DOEPCTL_DPID (1U<<16) /**< Endpoint data PID. */
-#define DOEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */
-#define DOEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */
-#define DOEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */
-/** @} */
-
-/**
- * @name DOEPINT register bit definitions
- * @{
- */
-#define DOEPINT_B2BSTUP (1U<<6) /**< Back-to-back SETUP packets
- received. */
-#define DOEPINT_OTEPDIS (1U<<4) /**< OUT token received when
- endpoint disabled. */
-#define DOEPINT_STUP (1U<<3) /**< SETUP phase done. */
-#define DOEPINT_EPDISD (1U<<1) /**< Endpoint disabled
- interrupt. */
-#define DOEPINT_XFRC (1U<<0) /**< Transfer completed
- interrupt. */
-/** @} */
-
-/**
- * @name DOEPTSIZ register bit definitions
- * @{
- */
-#define DOEPTSIZ_RXDPID_MASK (3U<<29) /**< Received data PID mask. */
-#define DOEPTSIZ_RXDPID(n) ((n)<<29) /**< Received data PID value. */
-#define DOEPTSIZ_STUPCNT_MASK (3U<<29) /**< SETUP packet count mask. */
-#define DOEPTSIZ_STUPCNT(n) ((n)<<29) /**< SETUP packet count value. */
-#define DOEPTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */
-#define DOEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
-#define DOEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */
-#define DOEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
-/** @} */
-
-/**
- * @name PCGCCTL register bit definitions
- * @{
- */
-#define PCGCCTL_PHYSUSP (1U<<4) /**< PHY Suspended. */
-#define PCGCCTL_GATEHCLK (1U<<1) /**< Gate HCLK. */
-#define PCGCCTL_STPPCLK (1U<<0) /**< Stop PCLK. */
-/** @} */
-
-/**
- * @brief OTG_FS registers block memory address.
- */
-#define OTG_FS_ADDR 0x50000000
-
-/**
- * @brief OTG_HS registers block memory address.
- */
-#define OTG_HS_ADDR 0x40040000
-
-/**
- * @brief Accesses to the OTG_FS registers block.
- */
-#define OTG_FS ((stm32_otg_t *)OTG_FS_ADDR)
-
-/**
- * @brief Accesses to the OTG_HS registers block.
- */
-#define OTG_HS ((stm32_otg_t *)OTG_HS_ADDR)
-
-#endif /* STM32_OTG_H */
-
-/** @} */
diff --git a/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c
index 8947490..7981695 100644
--- a/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c
+++ b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -21,6 +21,53 @@
#include "usbh/internal.h"
#include <string.h>
+#if STM32_USBH_USE_OTG1
+#if !defined(STM32_OTG1_CHANNELS_NUMBER)
+#error "STM32_OTG1_CHANNELS_NUMBER must be defined"
+#endif
+#if !defined(STM32_OTG1_RXFIFO_SIZE)
+#define STM32_OTG1_RXFIFO_SIZE 1024
+#endif
+#if !defined(STM32_OTG1_PTXFIFO_SIZE)
+#define STM32_OTG1_PTXFIFO_SIZE 128
+#endif
+#if !defined(STM32_OTG1_NPTXFIFO_SIZE)
+#define STM32_OTG1_NPTXFIFO_SIZE 128
+#endif
+#if (STM32_OTG1_RXFIFO_SIZE + STM32_OTG1_PTXFIFO_SIZE + STM32_OTG1_NPTXFIFO_SIZE) > (STM32_OTG1_FIFO_MEM_SIZE * 4)
+#error "Not enough memory in OTG1 implementation"
+#elif (STM32_OTG1_RXFIFO_SIZE + STM32_OTG1_PTXFIFO_SIZE + STM32_OTG1_NPTXFIFO_SIZE) < (STM32_OTG1_FIFO_MEM_SIZE * 4)
+#warning "Spare memory in OTG1; could enlarge RX, PTX or NPTX FIFO sizes"
+#endif
+#if (STM32_OTG1_RXFIFO_SIZE % 4) || (STM32_OTG1_PTXFIFO_SIZE % 4) || (STM32_OTG1_NPTXFIFO_SIZE % 4)
+#error "FIFO sizes must be a multiple of 32-bit words"
+#endif
+#endif
+
+#if STM32_USBH_USE_OTG2
+#if !defined(STM32_OTG2_CHANNELS_NUMBER)
+#error "STM32_OTG2_CHANNELS_NUMBER must be defined"
+#endif
+#if !defined(STM32_OTG2_RXFIFO_SIZE)
+#define STM32_OTG2_RXFIFO_SIZE 2048
+#endif
+#if !defined(STM32_OTG2_PTXFIFO_SIZE)
+#define STM32_OTG2_PTXFIFO_SIZE 1024
+#endif
+#if !defined(STM32_OTG2_NPTXFIFO_SIZE)
+#define STM32_OTG2_NPTXFIFO_SIZE 1024
+#endif
+#if (STM32_OTG2_RXFIFO_SIZE + STM32_OTG2_PTXFIFO_SIZE + STM32_OTG2_NPTXFIFO_SIZE) > (STM32_OTG2_FIFO_MEM_SIZE * 4)
+#error "Not enough memory in OTG2 implementation"
+#elif (STM32_OTG2_RXFIFO_SIZE + STM32_OTG2_PTXFIFO_SIZE + STM32_OTG2_NPTXFIFO_SIZE) < (STM32_OTG2_FIFO_MEM_SIZE * 4)
+#warning "Spare memory in OTG2; could enlarge RX, PTX or NPTX FIFO sizes"
+#endif
+#if (STM32_OTG2_RXFIFO_SIZE % 4) || (STM32_OTG2_PTXFIFO_SIZE % 4) || (STM32_OTG2_NPTXFIFO_SIZE % 4)
+#error "FIFO sizes must be a multiple of 32-bit words"
+#endif
+#endif
+
+
#if USBH_LLD_DEBUG_ENABLE_TRACE
#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
@@ -492,7 +539,7 @@ static uint32_t _write_packet(struct list_head *list, uint32_t space_available)
void usbh_lld_ep_object_init(usbh_ep_t *ep) {
/* CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT)
- * STALL si sólo DAT/STAT si si si si no no ep->type != ISO && (ep->type != CTRL || ctrlphase != SETUP)
+ * STALL si solo DAT/STAT si si si si no no ep->type != ISO && (ep->type != CTRL || ctrlphase != SETUP)
* ACK si si si si si si no no ep->type != ISO
* NAK si si si si si si no no ep->type != ISO
* BBERR si no si no si no si no ep->in
@@ -563,6 +610,11 @@ void usbh_lld_ep_close(usbh_ep_t *ep) {
osalOsRescheduleS();
}
+bool usbh_lld_ep_reset(usbh_ep_t *ep) {
+ ep->dt_mask = HCTSIZ_DPID_DATA0;
+ return TRUE;
+}
+
void usbh_lld_urb_submit(usbh_urb_t *urb) {
usbh_ep_t *const ep = urb->ep;
@@ -596,17 +648,20 @@ bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status) {
if (hcm->halt_reason == USBH_LLD_HALTREASON_NONE) {
/* The channel is not being halted */
+ uinfof("\t%s: usbh_lld_urb_abort: channel is not being halted", hcm->ep->name);
urb->status = status;
_halt_channel(ep->device->host, hcm, USBH_LLD_HALTREASON_ABORT);
} else {
/* The channel is being halted, so we can't re-halt it. The CHH interrupt will
* be in charge of completing the transfer, but the URB will not have the specified status.
*/
+ uinfof("\t%s: usbh_lld_urb_abort: channel is being halted", hcm->ep->name);
}
return FALSE;
}
/* This URB is active, we can cancel it now */
+ uinfof("\t%s: usbh_lld_urb_abort: URB is not active", hcm->ep->name);
_transfer_completedI(ep, urb, status);
return TRUE;
@@ -855,8 +910,12 @@ static inline void _chh_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_
break;
case USBH_LLD_HALTREASON_STALL:
- if ((ep->type == USBH_EPTYPE_CTRL) && (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_SETUP)) {
- uerrf("\t%s: Faulty device: STALLed SETUP phase", ep->name);
+ if (ep->type == USBH_EPTYPE_CTRL) {
+ if (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_SETUP) {
+ uerrf("\t%s: Faulty device: STALLed SETUP phase", ep->name);
+ }
+ } else {
+ ep->status = USBH_EPSTATUS_HALTED;
}
_transfer_completed(ep, urb, USBH_URBSTATUS_STALL);
break;
@@ -926,10 +985,15 @@ static inline void _hcint_int(USBHDriver *host) {
haint = host->otg->HAINT;
haint &= host->otg->HAINTMSK;
+#if USBH_LLD_DEBUG_ENABLE_ERRORS
if (!haint) {
- uerrf("HAINT=%08x, HAINTMSK=%08x", host->otg->HAINT, host->otg->HAINTMSK);
+ uint32_t a, b;
+ a = host->otg->HAINT;
+ b = host->otg->HAINTMSK;
+ uerrf("HAINT=%08x, HAINTMSK=%08x", a, b);
return;
}
+#endif
#if 1 //channel lookup loop
uint8_t i;
@@ -1186,11 +1250,17 @@ static void usb_lld_serve_interrupt(USBHDriver *host) {
}
gintsts &= otg->GINTMSK;
+#if USBH_DEBUG_ENABLE_WARNINGS
if (!gintsts) {
- uwarnf("GINTSTS=%08x, GINTMSK=%08x", otg->GINTSTS, otg->GINTMSK);
+ uint32_t a, b;
+ a = otg->GINTSTS;
+ b = otg->GINTMSK;
+ uwarnf("GINTSTS=%08x, GINTMSK=%08x", a, b);
return;
}
-// otg->GINTMSK &= ~(GINTMSK_NPTXFEM | GINTMSK_PTXFEM);
+#endif
+
+ // otg->GINTMSK &= ~(GINTMSK_NPTXFEM | GINTMSK_PTXFEM);
otg->GINTSTS = gintsts;
if (gintsts & GINTSTS_SOF)
@@ -1437,6 +1507,7 @@ static void _usbh_start(USBHDriver *usbh) {
}
#endif
#endif
+#undef HNPTXFSIZ
otg_txfifo_flush(usbh, 0x10);
otg_rxfifo_flush(usbh);
@@ -1478,18 +1549,18 @@ usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestTy
break;
case ClearPortFeature:
- chDbgAssert(windex == 1, "invalid windex");
+ osalDbgAssert(windex == 1, "invalid windex");
osalSysLock();
switch (wvalue) {
case USBH_PORT_FEAT_ENABLE:
case USBH_PORT_FEAT_SUSPEND:
case USBH_PORT_FEAT_POWER:
- chDbgAssert(0, "unimplemented"); /* TODO */
+ osalDbgAssert(0, "unimplemented"); /* TODO */
break;
case USBH_PORT_FEAT_INDICATOR:
- chDbgAssert(0, "unsupported");
+ osalDbgAssert(0, "unsupported");
break;
case USBH_PORT_FEAT_C_CONNECTION:
@@ -1541,7 +1612,7 @@ usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestTy
break;
case GetPortStatus:
- chDbgAssert(windex == 1, "invalid windex");
+ osalDbgAssert(windex == 1, "invalid windex");
osalDbgCheck(wlength >= 4);
osalSysLock();
*(uint32_t *)buf = usbh->rootport.lld_status | (usbh->rootport.lld_c_status << 16);
@@ -1550,17 +1621,17 @@ usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestTy
break;
case SetHubFeature:
- chDbgAssert(0, "unsupported");
+ osalDbgAssert(0, "unsupported");
break;
case SetPortFeature:
- chDbgAssert(windex == 1, "invalid windex");
+ osalDbgAssert(windex == 1, "invalid windex");
switch (wvalue) {
case USBH_PORT_FEAT_TEST:
case USBH_PORT_FEAT_SUSPEND:
case USBH_PORT_FEAT_POWER:
- chDbgAssert(0, "unimplemented"); /* TODO */
+ osalDbgAssert(0, "unimplemented"); /* TODO */
break;
case USBH_PORT_FEAT_RESET: {
@@ -1580,7 +1651,7 @@ usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestTy
} break;
case USBH_PORT_FEAT_INDICATOR:
- chDbgAssert(0, "unsupported");
+ osalDbgAssert(0, "unsupported");
break;
default:
diff --git a/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h
index 15413b4..0cdf79c 100644
--- a/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h
+++ b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -127,25 +127,26 @@ typedef struct stm32_hc_management {
"use USBH_DEFINE_BUFFER() to declare the IO buffers"); \
} while (0)
-
-
void usbh_lld_init(void);
void usbh_lld_start(USBHDriver *usbh);
void usbh_lld_ep_object_init(usbh_ep_t *ep);
void usbh_lld_ep_open(usbh_ep_t *ep);
void usbh_lld_ep_close(usbh_ep_t *ep);
+bool usbh_lld_ep_reset(usbh_ep_t *ep);
void usbh_lld_urb_submit(usbh_urb_t *urb);
bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status);
usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestType, uint8_t bRequest,
uint16_t wvalue, uint16_t windex, uint16_t wlength, uint8_t *buf);
uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh);
-#define usbh_lld_epreset(ep) do {(ep)->dt_mask = HCTSIZ_DPID_DATA0;} while (0);
-
#ifdef __IAR_SYSTEMS_ICC__
-#define USBH_LLD_DEFINE_BUFFER(type, name) type name
+#define USBH_LLD_DEFINE_BUFFER(var) _Pragma("data_alignment=4") var
+#define USBH_LLD_DECLARE_STRUCT_MEMBER_H1(x, y) x ## y
+#define USBH_LLD_DECLARE_STRUCT_MEMBER_H2(x, y) USBH_LLD_DECLARE_STRUCT_MEMBER_H1(x, y)
+#define USBH_LLD_DECLARE_STRUCT_MEMBER(member) unsigned int USBH_LLD_DECLARE_STRUCT_MEMBER_H2(dummy_align_, __COUNTER__); member
#else
-#define USBH_LLD_DEFINE_BUFFER(type, name) type name __attribute__((aligned(4)))
+#define USBH_LLD_DEFINE_BUFFER(var) var __attribute__((aligned(4)))
+#define USBH_LLD_DECLARE_STRUCT_MEMBER(member) member __attribute__((aligned(4)))
#endif
#endif
diff --git a/os/hal/src/hal_usbh.c b/os/hal/src/hal_usbh.c
index befe17f..d242086 100644
--- a/os/hal/src/hal_usbh.c
+++ b/os/hal/src/hal_usbh.c
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -19,10 +19,17 @@
#if HAL_USE_USBH
-#include "usbh/dev/hub.h"
#include "usbh/internal.h"
#include <string.h>
+//devices
+#include "usbh/dev/hub.h"
+#include "usbh/dev/aoa.h"
+#include "usbh/dev/ftdi.h"
+#include "usbh/dev/msd.h"
+#include "usbh/dev/hid.h"
+#include "usbh/dev/uvc.h"
+
#if USBH_DEBUG_ENABLE_TRACE
#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
@@ -107,11 +114,23 @@ void usbhObjectInit(USBHDriver *usbh) {
}
void usbhInit(void) {
+#if HAL_USBH_USE_FTDI
+ usbhftdiInit();
+#endif
+#if HAL_USBH_USE_AOA
+ usbhaoaInit();
+#endif
+#if HAL_USBH_USE_MSD
+ usbhmsdInit();
+#endif
+#if HAL_USBH_USE_HID
+ usbhhidInit();
+#endif
+#if HAL_USBH_USE_UVC
+ usbhuvcInit();
+#endif
#if HAL_USBH_USE_HUB
- uint8_t i;
- for (i = 0; i < HAL_USBHHUB_MAX_INSTANCES; i++) {
- usbhhubObjectInit(&USBHHUBD[i]);
- }
+ usbhhubInit();
#endif
usbh_lld_init();
}
@@ -128,7 +147,6 @@ void usbhStart(USBHDriver *usbh) {
osalSysUnlock();
}
-
void usbhStop(USBHDriver *usbh) {
//TODO: implement
(void)usbh;
@@ -181,6 +199,25 @@ static void _ep0_object_init(usbh_device_t *dev, uint16_t wMaxPacketSize) {
usbhEPSetName(&dev->ctrl, "DEV[CTRL]");
}
+bool usbhEPReset(usbh_ep_t *ep) {
+ osalDbgCheck(ep != NULL);
+ osalDbgAssert((ep->status == USBH_EPSTATUS_OPEN) || (ep->status == USBH_EPSTATUS_HALTED), "invalid state");
+ osalDbgAssert(ep->type != USBH_EPTYPE_CTRL, "don't need to reset control endpoint");
+
+ usbh_urbstatus_t ret = usbhControlRequest(ep->device,
+ USBH_REQTYPE_STANDARDOUT(USBH_REQTYPE_RECIP_ENDPOINT),
+ USBH_REQ_CLEAR_FEATURE,
+ 0, ep->address | (ep->in ? 0x80 : 0x00), 0, 0);
+
+ /* TODO: GET_STATUS to see if endpoint is still halted */
+ osalSysLock();
+ if ((ret == USBH_URBSTATUS_OK) && usbh_lld_ep_reset(ep)) {
+ osalSysUnlock();
+ return HAL_SUCCESS;
+ }
+ osalSysUnlock();
+ return HAL_FAILED;
+}
/*===========================================================================*/
/* URB API. */
@@ -258,7 +295,6 @@ bool _usbh_urb_abortI(usbh_urb_t *urb, usbh_urbstatus_t status) {
_usbh_urb_completeI(urb, status);
return TRUE;
-// case USBH_URBSTATUS_QUEUED:
case USBH_URBSTATUS_PENDING:
return usbh_lld_urb_abort(urb, status);
}
@@ -271,11 +307,18 @@ void _usbh_urb_abort_and_waitS(usbh_urb_t *urb, usbh_urbstatus_t status) {
if (_usbh_urb_abortI(urb, status) == FALSE) {
uwarn("URB wasn't aborted immediately, suspend");
osalThreadSuspendS(&urb->abortingThread);
- urb->abortingThread = 0;
- } else {
+ osalDbgAssert(urb->abortingThread == 0, "maybe we should uncomment the line below");
+ //urb->abortingThread = 0;
+ }
+#if !(USBH_DEBUG_ENABLE && USBH_DEBUG_ENABLE_WARNINGS)
+ else {
osalOsRescheduleS();
}
+#else
uwarn("URB aborted");
+ osalOsRescheduleS(); /* debug printing functions call I-class functions inside
+ which may cause a priority violation without this call */
+#endif
}
bool usbhURBCancelI(usbh_urb_t *urb) {
@@ -295,9 +338,9 @@ msg_t usbhURBWaitTimeoutS(usbh_urb_t *urb, systime_t timeout) {
switch (urb->status) {
case USBH_URBSTATUS_INITIALIZED:
case USBH_URBSTATUS_PENDING:
-// case USBH_URBSTATUS_QUEUED:
ret = osalThreadSuspendTimeoutS(&urb->waitingThread, timeout);
- urb->waitingThread = 0;
+ osalDbgAssert(urb->waitingThread == 0, "maybe we should uncomment the line below");
+ //urb->waitingThread = 0;
break;
case USBH_URBSTATUS_OK:
@@ -382,7 +425,8 @@ usbh_urbstatus_t usbhControlRequestExtended(usbh_device_t *dev,
uint32_t *actual_len,
systime_t timeout) {
- _check_dev(dev);
+ if (!dev) return USBH_URBSTATUS_DISCONNECTED;
+
osalDbgCheck(req != NULL);
usbh_urb_t urb;
@@ -408,7 +452,7 @@ usbh_urbstatus_t usbhControlRequest(usbh_device_t *dev,
uint16_t wLength,
uint8_t *buff) {
- const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = {
+ USBH_DEFINE_BUFFER(const usbh_control_request_t req) = {
bmRequestType,
bRequest,
wValue,
@@ -422,27 +466,19 @@ usbh_urbstatus_t usbhControlRequest(usbh_device_t *dev,
/* Standard request helpers. */
/*===========================================================================*/
-#define USBH_GET_DESCRIPTOR(type, value, index) \
- USBH_STANDARDIN(type, \
- USBH_REQ_GET_DESCRIPTOR, \
- value, \
- index) \
-
-#define USBH_GETDEVICEDESCRIPTOR \
- USBH_GET_DESCRIPTOR(USBH_REQTYPE_DEVICE, (USBH_DT_DEVICE << 8) | 0, 0)
-
-#define USBH_GETCONFIGURATIONDESCRIPTOR(index) \
- USBH_GET_DESCRIPTOR(USBH_REQTYPE_DEVICE, (USBH_DT_CONFIG << 8) | index, 0)
-
-#define USBH_GETSTRINGDESCRIPTOR(index, langID) \
- USBH_GET_DESCRIPTOR(USBH_REQTYPE_DEVICE, (USBH_DT_STRING << 8) | index, langID)
-
bool usbhStdReqGetDeviceDescriptor(usbh_device_t *dev,
uint16_t wLength,
uint8_t *buf) {
usbh_device_descriptor_t *desc;
- usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GETDEVICEDESCRIPTOR, wLength, buf);
+
+ usbh_urbstatus_t ret = usbhControlRequest(dev,
+ USBH_REQTYPE_STANDARDIN(USBH_REQTYPE_RECIP_DEVICE),
+ USBH_REQ_GET_DESCRIPTOR,
+ (USBH_DT_DEVICE << 8) | 0, 0,
+ wLength, buf);
+
desc = (usbh_device_descriptor_t *)buf;
+
if ((ret != USBH_URBSTATUS_OK)
|| (desc->bLength != USBH_DT_DEVICE_SIZE)
|| (desc->bDescriptorType != USBH_DT_DEVICE)) {
@@ -455,8 +491,15 @@ bool usbhStdReqGetConfigurationDescriptor(usbh_device_t *dev,
uint8_t index,
uint16_t wLength,
uint8_t *buf) {
- usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GETCONFIGURATIONDESCRIPTOR(index), wLength, buf);
+
+ usbh_urbstatus_t ret = usbhControlRequest(dev,
+ USBH_REQTYPE_STANDARDIN(USBH_REQTYPE_RECIP_DEVICE),
+ USBH_REQ_GET_DESCRIPTOR,
+ (USBH_DT_CONFIG << 8) | index, 0,
+ wLength, buf);
+
usbh_config_descriptor_t *const desc = (usbh_config_descriptor_t *)buf;
+
if ((ret != USBH_URBSTATUS_OK)
|| (desc->bLength < USBH_DT_CONFIG_SIZE)
|| (desc->bDescriptorType != USBH_DT_CONFIG)) {
@@ -473,7 +516,13 @@ bool usbhStdReqGetStringDescriptor(usbh_device_t *dev,
osalDbgAssert(wLength >= USBH_DT_STRING_SIZE, "wrong size");
usbh_string_descriptor_t *desc = (usbh_string_descriptor_t *)buf;
- usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GETSTRINGDESCRIPTOR(index, langID), wLength, buf);
+
+ usbh_urbstatus_t ret = usbhControlRequest(dev,
+ USBH_REQTYPE_STANDARDIN(USBH_REQTYPE_RECIP_DEVICE),
+ USBH_REQ_GET_DESCRIPTOR,
+ (USBH_DT_STRING << 8) | index, langID,
+ wLength, buf);
+
if ((ret != USBH_URBSTATUS_OK)
|| (desc->bLength < USBH_DT_STRING_SIZE)
|| (desc->bDescriptorType != USBH_DT_STRING)) {
@@ -482,25 +531,17 @@ bool usbhStdReqGetStringDescriptor(usbh_device_t *dev,
return HAL_SUCCESS;
}
-
-
-#define USBH_SET_INTERFACE(interface, alt) \
- USBH_STANDARDOUT(USBH_REQTYPE_INTERFACE, \
- USBH_REQ_SET_INTERFACE, \
- alt, \
- interface) \
-
-#define USBH_GET_INTERFACE(interface) \
- USBH_STANDARDIN(USBH_REQTYPE_INTERFACE, \
- USBH_REQ_GET_INTERFACE, \
- 0, \
- interface) \
-
bool usbhStdReqSetInterface(usbh_device_t *dev,
uint8_t bInterfaceNumber,
uint8_t bAlternateSetting) {
- usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_SET_INTERFACE(bInterfaceNumber, bAlternateSetting), 0, NULL);
+ usbh_urbstatus_t ret = usbhControlRequest(dev,
+ USBH_REQTYPE_STANDARDOUT(USBH_REQTYPE_RECIP_INTERFACE),
+ USBH_REQ_SET_INTERFACE,
+ bAlternateSetting,
+ bInterfaceNumber,
+ 0, NULL);
+
if (ret != USBH_URBSTATUS_OK)
return HAL_FAILED;
@@ -511,9 +552,15 @@ bool usbhStdReqGetInterface(usbh_device_t *dev,
uint8_t bInterfaceNumber,
uint8_t *bAlternateSetting) {
- USBH_DEFINE_BUFFER(uint8_t, alt);
+ USBH_DEFINE_BUFFER(uint8_t alt);
+
+ usbh_urbstatus_t ret = usbhControlRequest(dev,
+ USBH_REQTYPE_STANDARDIN(USBH_REQTYPE_RECIP_INTERFACE),
+ USBH_REQ_GET_INTERFACE,
+ 0,
+ bInterfaceNumber,
+ 1, &alt);
- usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GET_INTERFACE(bInterfaceNumber), 1, &alt);
if (ret != USBH_URBSTATUS_OK)
return HAL_FAILED;
@@ -558,7 +605,8 @@ static void _device_initialize(usbh_device_t *dev, usbh_devspeed_t speed) {
static bool _device_setaddress(usbh_device_t *dev, uint8_t address) {
usbh_urbstatus_t ret = usbhControlRequest(dev,
- USBH_STANDARDOUT(USBH_REQTYPE_DEVICE, USBH_REQ_SET_ADDRESS, address, 0),
+ USBH_REQTYPE_STANDARDOUT(USBH_REQTYPE_RECIP_DEVICE),
+ USBH_REQ_SET_ADDRESS, address, 0,
0,
0);
if (ret != USBH_URBSTATUS_OK)
@@ -611,22 +659,12 @@ static void _device_free_full_cfgdesc(usbh_device_t *dev) {
}
}
-
-#define USBH_SET_CONFIGURATION(type, value, index) \
- USBH_STANDARDOUT(type, \
- USBH_REQ_SET_CONFIGURATION, \
- value, \
- index) \
-
-#define USBH_SETDEVICECONFIGURATION(index) \
- USBH_SET_CONFIGURATION(USBH_REQTYPE_DEVICE, index, 0)
-
-
static bool _device_set_configuration(usbh_device_t *dev, uint8_t configuration) {
usbh_urbstatus_t ret = usbhControlRequest(dev,
- USBH_SETDEVICECONFIGURATION(configuration),
- 0,
- 0);
+ USBH_REQTYPE_STANDARDOUT(USBH_REQTYPE_RECIP_DEVICE),
+ USBH_REQ_SET_CONFIGURATION,
+ configuration,
+ 0, 0, 0);
if (ret != USBH_URBSTATUS_OK)
return HAL_FAILED;
return HAL_SUCCESS;
@@ -720,7 +758,7 @@ static bool _device_enumerate(usbh_device_t *dev) {
#if USBH_DEBUG_ENABLE && USBH_DEBUG_ENABLE_INFO
void usbhDevicePrintInfo(usbh_device_t *dev) {
- USBH_DEFINE_BUFFER(char, str[64]);
+ USBH_DEFINE_BUFFER(char str[64]);
usbh_device_descriptor_t *const desc = &dev->devDesc;
uinfo("----- Device info -----");
@@ -856,7 +894,7 @@ static void _port_reset(usbh_port_t *port) {
#if HAL_USBH_USE_HUB
port->hub,
#endif
- USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
+ USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_OTHER,
USBH_REQ_SET_FEATURE,
USBH_PORT_FEAT_RESET,
port->number,
@@ -870,7 +908,7 @@ static void _port_update_status(usbh_port_t *port) {
#if HAL_USBH_USE_HUB
port->hub,
#endif
- USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
+ USBH_REQTYPE_DIR_IN | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_OTHER,
USBH_REQ_GET_STATUS,
0,
port->number,
@@ -934,7 +972,7 @@ static void _port_connected(usbh_port_t *port) {
uint8_t i;
uint8_t retries;
usbh_devspeed_t speed;
- USBH_DEFINE_BUFFER(usbh_string_descriptor_t, strdesc);
+ USBH_DEFINE_BUFFER(usbh_string_descriptor_t strdesc);
uinfof("Port %d connected, wait debounce...", port->number);
@@ -1086,7 +1124,7 @@ static void _hub_update_status(USBHDriver *host, USBHHubDriver *hub) {
uint32_t stat;
if (usbhhubControlRequest(host,
hub,
- USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE,
+ USBH_REQTYPE_DIR_IN | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_DEVICE,
USBH_REQ_GET_STATUS,
0,
0,
@@ -1274,8 +1312,17 @@ static const usbh_classdriverinfo_t *usbh_classdrivers_lookup[] = {
#if HAL_USBH_USE_MSD
&usbhmsdClassDriverInfo,
#endif
+#if HAL_USBH_USE_HID
+ &usbhhidClassDriverInfo,
+#endif
+#if HAL_USBH_USE_UVC
+ &usbhuvcClassDriverInfo,
+#endif
#if HAL_USBH_USE_HUB
- &usbhhubClassDriverInfo
+ &usbhhubClassDriverInfo,
+#endif
+#if HAL_USBH_USE_AOA
+ &usbhaoaClassDriverInfo, /* Leave always last */
#endif
};
@@ -1302,7 +1349,7 @@ static bool _classdriver_load(usbh_device_t *dev, uint8_t class,
#if HAL_USBH_USE_IAD
/* special case: */
if (info == &usbhiadClassDriverInfo)
- return HAL_SUCCESS;
+ goto success; //return HAL_SUCCESS;
#endif
if (drv != NULL)
@@ -1313,9 +1360,11 @@ static bool _classdriver_load(usbh_device_t *dev, uint8_t class,
success:
/* Link this driver to the device */
- drv->next = dev->drivers;
- dev->drivers = drv;
- drv->dev = dev;
+ if (!drv->dev) {
+ drv->next = dev->drivers;
+ dev->drivers = drv;
+ drv->dev = dev;
+ }
return HAL_SUCCESS;
}
diff --git a/os/hal/src/usbh/hal_usbh_aoa.c b/os/hal/src/usbh/hal_usbh_aoa.c
new file mode 100644
index 0000000..1fa49f8
--- /dev/null
+++ b/os/hal/src/usbh/hal_usbh_aoa.c
@@ -0,0 +1,678 @@
+/*
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "hal.h"
+
+#if HAL_USBH_USE_AOA
+
+#if !HAL_USE_USBH
+#error "USBHAOA needs USBH"
+#endif
+
+#include <string.h>
+#include "usbh/dev/aoa.h"
+#include "usbh/internal.h"
+
+//#pragma GCC optimize("Og")
+
+
+#if USBHAOA_DEBUG_ENABLE_TRACE
+#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
+#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
+#else
+#define udbgf(f, ...) do {} while(0)
+#define udbg(f, ...) do {} while(0)
+#endif
+
+#if USBHAOA_DEBUG_ENABLE_INFO
+#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
+#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
+#else
+#define uinfof(f, ...) do {} while(0)
+#define uinfo(f, ...) do {} while(0)
+#endif
+
+#if USBHAOA_DEBUG_ENABLE_WARNINGS
+#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
+#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
+#else
+#define uwarnf(f, ...) do {} while(0)
+#define uwarn(f, ...) do {} while(0)
+#endif
+
+#if USBHAOA_DEBUG_ENABLE_ERRORS
+#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
+#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
+#else
+#define uerrf(f, ...) do {} while(0)
+#define uerr(f, ...) do {} while(0)
+#endif
+
+
+/*===========================================================================*/
+/* Constants */
+/*===========================================================================*/
+
+#if !defined(HAL_USBHAOA_DEFAULT_MANUFACTURER)
+#define HAL_USBHAOA_DEFAULT_MANUFACTURER "ChibiOS"
+#endif
+
+#if !defined(HAL_USBHAOA_DEFAULT_MODEL)
+#define HAL_USBHAOA_DEFAULT_MODEL "USBH AOA Driver"
+#endif
+
+#if !defined(HAL_USBHAOA_DEFAULT_DESCRIPTION)
+#define HAL_USBHAOA_DEFAULT_DESCRIPTION "ChibiOS USBH AOA Driver"
+#endif
+
+#if !defined(HAL_USBHAOA_DEFAULT_VERSION)
+#define HAL_USBHAOA_DEFAULT_VERSION CH_KERNEL_VERSION
+#endif
+
+#if !defined(HAL_USBHAOA_DEFAULT_URI)
+#define HAL_USBHAOA_DEFAULT_URI NULL
+#endif
+
+#if !defined(HAL_USBHAOA_DEFAULT_SERIAL)
+#define HAL_USBHAOA_DEFAULT_SERIAL NULL
+#endif
+
+#if !defined(HAL_USBHAOA_DEFAULT_AUDIO_MODE)
+#define HAL_USBHAOA_DEFAULT_AUDIO_MODE USBHAOA_AUDIO_MODE_DISABLED
+#endif
+
+#define AOA_GOOGLE_VID 0x18D1
+#define AOA_GOOGLE_PID_ACCESSORY 0x2D00
+#define AOA_GOOGLE_PID_ACCESSORY_ABD 0x2D01
+#define AOA_GOOGLE_PID_AUDIO 0x2D02
+#define AOA_GOOGLE_PID_AUDIO_ABD 0x2D03
+#define AOA_GOOGLE_PID_ACCESSORY_AUDIO 0x2D04
+#define AOA_GOOGLE_PID_ACCESSORY_AUDIO_ABD 0x2D05
+
+#define AOA_ACCESSORY_GET_PROTOCOL 51
+#define AOA_ACCESSORY_SEND_STRING 52
+#define AOA_ACCESSORY_START 53
+
+#define AOA_SET_AUDIO_MODE 58
+
+static bool _get_protocol(usbh_device_t *dev, uint16_t *protocol);
+static bool _accessory_start(usbh_device_t *dev);
+static bool _set_audio_mode(usbh_device_t *dev, uint16_t mode);
+static bool _send_string(usbh_device_t *dev, uint8_t index, const char *string);
+
+
+static void _stop_channelS(USBHAOAChannel *aoacp);
+
+/*===========================================================================*/
+/* USB Class driver loader for AOA */
+/*===========================================================================*/
+USBHAOADriver USBHAOAD[HAL_USBHAOA_MAX_INSTANCES];
+
+static usbh_baseclassdriver_t *_aoa_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem);
+static void _aoa_unload(usbh_baseclassdriver_t *drv);
+
+static const usbh_classdriver_vmt_t class_driver_vmt = {
+ _aoa_load,
+ _aoa_unload
+};
+
+const usbh_classdriverinfo_t usbhaoaClassDriverInfo = {
+ 0xff, 0xff, 0xff, "AOA", &class_driver_vmt
+};
+
+#if defined(HAL_USBHAOA_FILTER_CALLBACK)
+extern usbhaoa_filter_callback_t HAL_USBHAOA_FILTER_CALLBACK;
+#endif
+
+static usbh_baseclassdriver_t *_aoa_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
+ int i;
+ USBHAOADriver *aoap;
+
+ if (dev->devDesc.idVendor != AOA_GOOGLE_VID) {
+ uint16_t protocol;
+ static const USBHAOAConfig config = {
+ {
+ HAL_USBHAOA_DEFAULT_MANUFACTURER,
+ HAL_USBHAOA_DEFAULT_MODEL,
+ HAL_USBHAOA_DEFAULT_DESCRIPTION,
+ HAL_USBHAOA_DEFAULT_VERSION,
+ HAL_USBHAOA_DEFAULT_URI,
+ HAL_USBHAOA_DEFAULT_SERIAL
+ },
+
+ {
+ HAL_USBHAOA_DEFAULT_AUDIO_MODE,
+ }
+ };
+
+ uinfo("AOA: Unrecognized VID");
+
+#if defined(HAL_USBHAOA_FILTER_CALLBACK)
+ if (!HAL_USBHAOA_FILTER_CALLBACK(dev, descriptor, rem, &config)) {
+ return NULL;
+ }
+#endif
+
+ uinfo("AOA: Try if it's an Android device");
+ if (_get_protocol(dev, &protocol) != HAL_SUCCESS) {
+ return NULL;
+ }
+ uinfof("AOA: Possible Android device found (protocol=%d)", protocol);
+
+ if (config.channel.manufacturer != NULL) {
+ if ((_send_string(dev, USBHAOA_ACCESSORY_STRING_MANUFACTURER, config.channel.manufacturer) != HAL_SUCCESS)
+ || (_send_string(dev, USBHAOA_ACCESSORY_STRING_MODEL, config.channel.model) != HAL_SUCCESS)
+ || (_send_string(dev, USBHAOA_ACCESSORY_STRING_DESCRIPTION, config.channel.description) != HAL_SUCCESS)
+ || (_send_string(dev, USBHAOA_ACCESSORY_STRING_VERSION, config.channel.version) != HAL_SUCCESS)
+ || (_send_string(dev, USBHAOA_ACCESSORY_STRING_URI, config.channel.uri) != HAL_SUCCESS)
+ || (_send_string(dev, USBHAOA_ACCESSORY_STRING_SERIAL, config.channel.serial) != HAL_SUCCESS)) {
+ uerr("AOA: Can't send string; abort start");
+ return NULL;
+ }
+ }
+
+ if (protocol > 1) {
+ if (_set_audio_mode(dev, (uint16_t)(config.audio.mode)) != HAL_SUCCESS) {
+ uerr("AOA: Can't set audio mode; abort channel start");
+ return NULL;
+ }
+ }
+
+ if (_accessory_start(dev) != HAL_SUCCESS) {
+ uerr("AOA: Can't start accessory; abort channel start");
+ }
+
+ return NULL;
+ }
+
+ /* AOAv2:
+ 0x2D00 accessory Provides two bulk endpoints for communicating with an Android application.
+ 0x2D01 accessory + adb For debugging purposes during accessory development. Available only if the user has enabled USB Debugging in the Android device settings.
+ 0x2D02 audio For streaming audio from an Android device to an accessory.
+ 0x2D03 audio + adb
+ 0x2D04 accessory + audio
+ 0x2D05 accessory + audio + adb
+ */
+
+ switch (dev->devDesc.idProduct) {
+ case AOA_GOOGLE_PID_ACCESSORY:
+ case AOA_GOOGLE_PID_ACCESSORY_ABD:
+// case AOA_GOOGLE_PID_AUDIO:
+// case AOA_GOOGLE_PID_AUDIO_ABD:
+ case AOA_GOOGLE_PID_ACCESSORY_AUDIO:
+ case AOA_GOOGLE_PID_ACCESSORY_AUDIO_ABD:
+ break;
+ default:
+ uerr("AOA: Unrecognized PID");
+ return NULL;
+ }
+
+ if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE))
+ return NULL;
+
+ const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t *)descriptor;
+
+ if ((ifdesc->bInterfaceClass != 0xff)
+ || (ifdesc->bInterfaceSubClass != 0xff)
+ || (ifdesc->bInterfaceProtocol != 0x00)
+ || (ifdesc->bNumEndpoints < 2)) {
+ uerr("AOA: This IF is not the Accessory IF");
+ return NULL;
+ }
+
+ uinfof("AOA: Found Accessory Interface #%d", ifdesc->bInterfaceNumber);
+
+ for (i = 0; i < HAL_USBHAOA_MAX_INSTANCES; i++) {
+ if (USBHAOAD[i].dev == NULL) {
+ aoap = &USBHAOAD[i];
+ goto alloc_ok;
+ }
+ }
+
+ uwarn("AOA: Can't alloc driver");
+
+ /* can't alloc */
+ return NULL;
+
+alloc_ok:
+ /* initialize the driver's variables */
+ usbhEPSetName(&dev->ctrl, "AOA[CTRL]");
+ aoap->state = USBHAOA_STATE_ACTIVE;
+
+ generic_iterator_t iep;
+ if_iterator_t iif;
+ iif.iad = 0;
+ iif.curr = descriptor;
+ iif.rem = rem;
+
+ aoap->channel.epin.status = USBH_EPSTATUS_UNINITIALIZED;
+ aoap->channel.epout.status = USBH_EPSTATUS_UNINITIALIZED;
+
+ for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) {
+ const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
+ if ((epdesc->bEndpointAddress & 0x80) && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
+ uinfof("AOA: BULK IN endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
+ usbhEPObjectInit(&aoap->channel.epin, dev, epdesc);
+ usbhEPSetName(&aoap->channel.epin, "AOA[BIN ]");
+ } else if (((epdesc->bEndpointAddress & 0x80) == 0)
+ && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
+ uinfof("AOA: BULK OUT endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
+ usbhEPObjectInit(&aoap->channel.epout, dev, epdesc);
+ usbhEPSetName(&aoap->channel.epout, "AOA[BOUT]");
+ } else {
+ uinfof("AOA: unsupported endpoint found: bEndpointAddress=%02x, bmAttributes=%02x",
+ epdesc->bEndpointAddress, epdesc->bmAttributes);
+ }
+ }
+
+ if ((aoap->channel.epin.status != USBH_EPSTATUS_CLOSED)
+ || (aoap->channel.epout.status != USBH_EPSTATUS_CLOSED)) {
+ uwarn("AOA: Couldn't find endpoints");
+ aoap->state = USBHAOA_STATE_STOP;
+ return NULL;
+ }
+
+ aoap->state = USBHAOA_STATE_READY;
+ aoap->channel.state = USBHAOA_CHANNEL_STATE_ACTIVE;
+ uwarn("AOA: Ready");
+ return (usbh_baseclassdriver_t *)aoap;
+}
+
+static void _aoa_unload(usbh_baseclassdriver_t *drv) {
+ osalDbgCheck(drv != NULL);
+ USBHAOADriver *const aoap = (USBHAOADriver *)drv;
+ osalSysLock();
+ _stop_channelS(&aoap->channel);
+ aoap->channel.state = USBHAOA_CHANNEL_STATE_STOP;
+ aoap->state = USBHAOA_STATE_STOP;
+ osalOsRescheduleS();
+ osalSysUnlock();
+}
+
+/* ------------------------------------ */
+/* Accessory data channel */
+/* ------------------------------------ */
+
+static void _submitOutI(USBHAOAChannel *aoacp, uint32_t len) {
+ udbgf("AOA: Submit OUT %d", len);
+ aoacp->oq_urb.requestedLength = len;
+ usbhURBObjectResetI(&aoacp->oq_urb);
+ usbhURBSubmitI(&aoacp->oq_urb);
+}
+
+static void _out_cb(usbh_urb_t *urb) {
+ USBHAOAChannel *const aoacp = (USBHAOAChannel *)urb->userData;
+ switch (urb->status) {
+ case USBH_URBSTATUS_OK:
+ aoacp->oq_ptr = aoacp->oq_buff;
+ aoacp->oq_counter = 64;
+ chThdDequeueNextI(&aoacp->oq_waiting, Q_OK);
+ chnAddFlagsI(aoacp, CHN_OUTPUT_EMPTY | CHN_TRANSMISSION_END);
+ return;
+ case USBH_URBSTATUS_DISCONNECTED:
+ uwarn("AOA: URB OUT disconnected");
+ chThdDequeueNextI(&aoacp->oq_waiting, Q_RESET);
+ chnAddFlagsI(aoacp, CHN_OUTPUT_EMPTY);
+ return;
+ default:
+ uerrf("AOA: URB OUT status unexpected = %d", urb->status);
+ break;
+ }
+ usbhURBObjectResetI(&aoacp->oq_urb);
+ usbhURBSubmitI(&aoacp->oq_urb);
+}
+
+static size_t _write_timeout(USBHAOAChannel *aoacp, const uint8_t *bp,
+ size_t n, systime_t timeout) {
+ chDbgCheck(n > 0U);
+
+ size_t w = 0;
+ chSysLock();
+ while (true) {
+ if (aoacp->state != USBHAOA_CHANNEL_STATE_READY) {
+ chSysUnlock();
+ return w;
+ }
+ while (usbhURBIsBusy(&aoacp->oq_urb)) {
+ if (chThdEnqueueTimeoutS(&aoacp->oq_waiting, timeout) != Q_OK) {
+ chSysUnlock();
+ return w;
+ }
+ }
+
+ *aoacp->oq_ptr++ = *bp++;
+ if (--aoacp->oq_counter == 0) {
+ _submitOutI(aoacp, 64);
+ chSchRescheduleS();
+ }
+ chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
+
+ w++;
+ if (--n == 0U)
+ return w;
+
+ chSysLock();
+ }
+}
+
+static msg_t _put_timeout(USBHAOAChannel *aoacp, uint8_t b, systime_t timeout) {
+
+ chSysLock();
+ if (aoacp->state != USBHAOA_CHANNEL_STATE_READY) {
+ chSysUnlock();
+ return Q_RESET;
+ }
+
+ while (usbhURBIsBusy(&aoacp->oq_urb)) {
+ msg_t msg = chThdEnqueueTimeoutS(&aoacp->oq_waiting, timeout);
+ if (msg < Q_OK) {
+ chSysUnlock();
+ return msg;
+ }
+ }
+
+ *aoacp->oq_ptr++ = b;
+ if (--aoacp->oq_counter == 0) {
+ _submitOutI(aoacp, 64);
+ chSchRescheduleS();
+ }
+ chSysUnlock();
+ return Q_OK;
+}
+
+static size_t _write(USBHAOAChannel *aoacp, const uint8_t *bp, size_t n) {
+ return _write_timeout(aoacp, bp, n, TIME_INFINITE);
+}
+
+static msg_t _put(USBHAOAChannel *aoacp, uint8_t b) {
+ return _put_timeout(aoacp, b, TIME_INFINITE);
+}
+
+static void _submitInI(USBHAOAChannel *aoacp) {
+ udbg("AOA: Submit IN");
+ usbhURBObjectResetI(&aoacp->iq_urb);
+ usbhURBSubmitI(&aoacp->iq_urb);
+}
+
+static void _in_cb(usbh_urb_t *urb) {
+ USBHAOAChannel *const aoacp = (USBHAOAChannel *)urb->userData;
+ switch (urb->status) {
+ case USBH_URBSTATUS_OK:
+ if (urb->actualLength == 0) {
+ udbgf("AOA: URB IN no data");
+ } else {
+ udbgf("AOA: URB IN data len=%d", urb->actualLength);
+ aoacp->iq_ptr = aoacp->iq_buff;
+ aoacp->iq_counter = urb->actualLength;
+ chThdDequeueNextI(&aoacp->iq_waiting, Q_OK);
+ chnAddFlagsI(aoacp, CHN_INPUT_AVAILABLE);
+ }
+ break;
+ case USBH_URBSTATUS_DISCONNECTED:
+ uwarn("AOA: URB IN disconnected");
+ chThdDequeueNextI(&aoacp->iq_waiting, Q_RESET);
+ break;
+ default:
+ uerrf("AOA: URB IN status unexpected = %d", urb->status);
+ _submitInI(aoacp);
+ break;
+ }
+}
+
+static size_t _read_timeout(USBHAOAChannel *aoacp, uint8_t *bp,
+ size_t n, systime_t timeout) {
+ size_t r = 0;
+
+ chDbgCheck(n > 0U);
+
+ chSysLock();
+ while (true) {
+ if (aoacp->state != USBHAOA_CHANNEL_STATE_READY) {
+ chSysUnlock();
+ return r;
+ }
+ while (aoacp->iq_counter == 0) {
+ if (!usbhURBIsBusy(&aoacp->iq_urb))
+ _submitInI(aoacp);
+ if (chThdEnqueueTimeoutS(&aoacp->iq_waiting, timeout) != Q_OK) {
+ chSysUnlock();
+ return r;
+ }
+ }
+ *bp++ = *aoacp->iq_ptr++;
+ if (--aoacp->iq_counter == 0) {
+ _submitInI(aoacp);
+ chSchRescheduleS();
+ }
+ chSysUnlock();
+
+ r++;
+ if (--n == 0U)
+ return r;
+
+ chSysLock();
+ }
+}
+
+static msg_t _get_timeout(USBHAOAChannel *aoacp, systime_t timeout) {
+ uint8_t b;
+
+ chSysLock();
+ if (aoacp->state != USBHAOA_CHANNEL_STATE_READY) {
+ chSysUnlock();
+ return Q_RESET;
+ }
+ while (aoacp->iq_counter == 0) {
+ if (!usbhURBIsBusy(&aoacp->iq_urb))
+ _submitInI(aoacp);
+ msg_t msg = chThdEnqueueTimeoutS(&aoacp->iq_waiting, timeout);
+ if (msg < Q_OK) {
+ chSysUnlock();
+ return msg;
+ }
+ }
+ b = *aoacp->iq_ptr++;
+ if (--aoacp->iq_counter == 0) {
+ _submitInI(aoacp);
+ chSchRescheduleS();
+ }
+ chSysUnlock();
+
+ return (msg_t)b;
+}
+
+static msg_t _get(USBHAOAChannel *aoacp) {
+ return _get_timeout(aoacp, TIME_INFINITE);
+}
+
+static size_t _read(USBHAOAChannel *aoacp, uint8_t *bp, size_t n) {
+ return _read_timeout(aoacp, bp, n, TIME_INFINITE);
+}
+
+static const struct AOADriverVMT async_channel_vmt = {
+ (size_t (*)(void *, const uint8_t *, size_t))_write,
+ (size_t (*)(void *, uint8_t *, size_t))_read,
+ (msg_t (*)(void *, uint8_t))_put,
+ (msg_t (*)(void *))_get,
+ (msg_t (*)(void *, uint8_t, systime_t))_put_timeout,
+ (msg_t (*)(void *, systime_t))_get_timeout,
+ (size_t (*)(void *, const uint8_t *, size_t, systime_t))_write_timeout,
+ (size_t (*)(void *, uint8_t *, size_t, systime_t))_read_timeout
+};
+
+static void _stop_channelS(USBHAOAChannel *aoacp) {
+ if (aoacp->state != USBHAOA_CHANNEL_STATE_READY)
+ return;
+ uwarn("AOA: Stop channel");
+ chVTResetI(&aoacp->vt);
+ usbhEPCloseS(&aoacp->epin);
+ usbhEPCloseS(&aoacp->epout);
+ chThdDequeueAllI(&aoacp->iq_waiting, Q_RESET);
+ chThdDequeueAllI(&aoacp->oq_waiting, Q_RESET);
+ chnAddFlagsI(aoacp, CHN_DISCONNECTED);
+ aoacp->state = USBHAOA_CHANNEL_STATE_ACTIVE;
+}
+
+static void _vt(void *p) {
+ USBHAOAChannel *const aoacp = (USBHAOAChannel *)p;
+ chSysLockFromISR();
+ uint32_t len = aoacp->oq_ptr - aoacp->oq_buff;
+ if (len && !usbhURBIsBusy(&aoacp->oq_urb)) {
+ _submitOutI(aoacp, len);
+ }
+ if ((aoacp->iq_counter == 0) && !usbhURBIsBusy(&aoacp->iq_urb)) {
+ _submitInI(aoacp);
+ }
+ chVTSetI(&aoacp->vt, MS2ST(16), _vt, aoacp);
+ chSysUnlockFromISR();
+}
+
+void usbhaoaChannelStart(USBHAOADriver *aoap) {
+
+ osalDbgCheck(aoap);
+
+ USBHAOAChannel *const aoacp = (USBHAOAChannel *)&aoap->channel;
+
+ osalDbgCheck(aoap->state == USBHAOA_STATE_READY);
+
+ osalDbgCheck((aoacp->state == USBHAOA_CHANNEL_STATE_ACTIVE)
+ || (aoacp->state == USBHAOA_CHANNEL_STATE_READY));
+
+ if (aoacp->state == USBHAOA_CHANNEL_STATE_READY)
+ return;
+
+ usbhURBObjectInit(&aoacp->oq_urb, &aoacp->epout, _out_cb, aoacp, aoacp->oq_buff, 0);
+ chThdQueueObjectInit(&aoacp->oq_waiting);
+ aoacp->oq_counter = 64;
+ aoacp->oq_ptr = aoacp->oq_buff;
+ usbhEPOpen(&aoacp->epout);
+
+ usbhURBObjectInit(&aoacp->iq_urb, &aoacp->epin, _in_cb, aoacp, aoacp->iq_buff, 64);
+ chThdQueueObjectInit(&aoacp->iq_waiting);
+ aoacp->iq_counter = 0;
+ aoacp->iq_ptr = aoacp->iq_buff;
+ usbhEPOpen(&aoacp->epin);
+ osalSysLock();
+ usbhURBSubmitI(&aoacp->iq_urb);
+ osalSysUnlock();
+
+ chVTObjectInit(&aoacp->vt);
+ chVTSet(&aoacp->vt, MS2ST(16), _vt, aoacp);
+
+ aoacp->state = USBHAOA_CHANNEL_STATE_READY;
+
+ osalEventBroadcastFlags(&aoacp->event, CHN_CONNECTED | CHN_OUTPUT_EMPTY);
+}
+
+void usbhaoaChannelStop(USBHAOADriver *aoap) {
+ osalDbgCheck((aoap->channel.state == USBHAOA_CHANNEL_STATE_ACTIVE)
+ || (aoap->channel.state == USBHAOA_CHANNEL_STATE_READY));
+ osalSysLock();
+ _stop_channelS(&aoap->channel);
+ osalOsRescheduleS();
+ osalSysUnlock();
+}
+
+/* ------------------------------------ */
+/* General AOA functions */
+/* ------------------------------------ */
+static bool _get_protocol(usbh_device_t *dev, uint16_t *protocol) {
+ USBH_DEFINE_BUFFER(uint16_t proto);
+
+ usbh_urbstatus_t ret = usbhControlRequest(dev,
+ USBH_REQTYPE_DIR_IN | USBH_REQTYPE_TYPE_VENDOR | USBH_REQTYPE_RECIP_DEVICE,
+ AOA_ACCESSORY_GET_PROTOCOL,
+ 0,
+ 0,
+ 2,
+ (uint8_t *)&proto);
+
+ if ((ret != USBH_URBSTATUS_OK) || (proto > 2))
+ return HAL_FAILED;
+
+ *protocol = proto;
+ return HAL_SUCCESS;
+}
+
+static bool _accessory_start(usbh_device_t *dev) {
+ usbh_urbstatus_t ret = usbhControlRequest(dev,
+ USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_VENDOR | USBH_REQTYPE_RECIP_DEVICE,
+ AOA_ACCESSORY_START,
+ 0,
+ 0,
+ 0,
+ NULL);
+
+ if (ret != USBH_URBSTATUS_OK)
+ return HAL_FAILED;
+
+ return HAL_SUCCESS;
+}
+
+static bool _set_audio_mode(usbh_device_t *dev, uint16_t mode) {
+ usbh_urbstatus_t ret = usbhControlRequest(dev,
+ USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_VENDOR | USBH_REQTYPE_RECIP_DEVICE,
+ AOA_SET_AUDIO_MODE,
+ mode,
+ 0,
+ 0,
+ NULL);
+
+ if (ret != USBH_URBSTATUS_OK)
+ return HAL_FAILED;
+
+ return HAL_SUCCESS;
+}
+
+static bool _send_string(usbh_device_t *dev, uint8_t index, const char *string)
+{
+ USBH_DEFINE_BUFFER(const char nullstr[1]) = {0};
+ if (string == NULL)
+ string = nullstr;
+
+ usbh_urbstatus_t ret = usbhControlRequest(dev,
+ USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_TYPE_VENDOR | USBH_REQTYPE_RECIP_DEVICE,
+ AOA_ACCESSORY_SEND_STRING,
+ 0,
+ index,
+ strlen(string) + 1,
+ (uint8_t *)string);
+
+ if (ret != USBH_URBSTATUS_OK)
+ return HAL_FAILED;
+
+ return HAL_SUCCESS;
+}
+
+void usbhaoaObjectInit(USBHAOADriver *aoap) {
+ osalDbgCheck(aoap != NULL);
+ memset(aoap, 0, sizeof(*aoap));
+ aoap->info = &usbhaoaClassDriverInfo;
+ aoap->state = USBHAOA_STATE_STOP;
+ aoap->channel.vmt = &async_channel_vmt;
+ osalEventObjectInit(&aoap->channel.event);
+ aoap->channel.state = USBHAOA_CHANNEL_STATE_STOP;
+}
+
+void usbhaoaInit(void) {
+ uint8_t i;
+ for (i = 0; i < HAL_USBHAOA_MAX_INSTANCES; i++) {
+ usbhaoaObjectInit(&USBHAOAD[i]);
+ }
+}
+
+#endif
diff --git a/os/hal/src/usbh/hal_usbh_debug.c b/os/hal/src/usbh/hal_usbh_debug.c
index 51ca166..7c4ff7d 100644
--- a/os/hal/src/usbh/hal_usbh_debug.c
+++ b/os/hal/src/usbh/hal_usbh_debug.c
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -17,15 +17,13 @@
#include "hal.h"
-#if HAL_USE_USBH
+#if HAL_USE_USBH && USBH_DEBUG_ENABLE
#include "ch.h"
#include "usbh/debug.h"
#include <stdarg.h>
#include "chprintf.h"
-#if USBH_DEBUG_ENABLE
-
#define MAX_FILLER 11
#define FLOAT_PRECISION 9
#define MPRINTF_USE_FLOAT 0
@@ -472,8 +470,8 @@ void usbDbgSystemHalted(void) {
}
}
-static void usb_debug_thread(void *p) {
- USBHDriver *host = (USBHDriver *)p;
+static void usb_debug_thread(void *arg) {
+ USBHDriver *host = (USBHDriver *)arg;
uint8_t state = 0;
chRegSetThreadName("USBH_DBG");
@@ -531,6 +529,5 @@ void usbDbgInit(USBHDriver *host) {
iqObjectInit(&USBH_DEBUG_USBHD.iq, USBH_DEBUG_USBHD.dbg_buff, sizeof(USBH_DEBUG_USBHD.dbg_buff), 0, 0);
chThdCreateStatic(USBH_DEBUG_USBHD.waDebug, sizeof(USBH_DEBUG_USBHD.waDebug), NORMALPRIO, usb_debug_thread, &USBH_DEBUG_USBHD);
}
-#endif
#endif
diff --git a/os/hal/src/usbh/hal_usbh_desciter.c b/os/hal/src/usbh/hal_usbh_desciter.c
index 63137d4..3695881 100644
--- a/os/hal/src/usbh/hal_usbh_desciter.c
+++ b/os/hal/src/usbh/hal_usbh_desciter.c
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -134,22 +134,18 @@ void cs_iter_next(generic_iterator_t *ics) {
if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
return;
- //for (;;) {
- rem -= curr[0];
- curr += curr[0];
+ rem -= curr[0];
+ curr += curr[0];
- if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
- return;
-
- if ((curr[1] == USBH_DT_INTERFACE_ASSOCIATION)
- || (curr[1] == USBH_DT_INTERFACE)
- || (curr[1] == USBH_DT_CONFIG)
- || (curr[1] == USBH_DT_ENDPOINT)) {
- return;
- }
+ if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
+ return;
- // break;
- //}
+ if ((curr[1] == USBH_DT_INTERFACE_ASSOCIATION)
+ || (curr[1] == USBH_DT_INTERFACE)
+ || (curr[1] == USBH_DT_CONFIG)
+ || (curr[1] == USBH_DT_ENDPOINT)) {
+ return;
+ }
ics->valid = 1;
ics->rem = rem;
diff --git a/os/hal/src/usbh/hal_usbh_ftdi.c b/os/hal/src/usbh/hal_usbh_ftdi.c
index 4bd7296..ce96958 100644
--- a/os/hal/src/usbh/hal_usbh_ftdi.c
+++ b/os/hal/src/usbh/hal_usbh_ftdi.c
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
*/
#include "hal.h"
-#include "hal_usbh.h"
#if HAL_USBH_USE_FTDI
@@ -105,6 +104,7 @@ static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *des
case 0x6011:
case 0x6014:
case 0x6015:
+ case 0xE2E6:
break;
default:
uerr("FTDI: Unrecognized PID");
@@ -114,8 +114,7 @@ static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *des
if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE))
return NULL;
- const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t * const)descriptor;
- if (ifdesc->bInterfaceNumber != 0) {
+ if (((const usbh_interface_descriptor_t *)descriptor)->bInterfaceNumber != 0) {
uwarn("FTDI: Will allocate driver along with IF #0");
}
@@ -211,7 +210,7 @@ alloc_ok:
}
-static void _stop(USBHFTDIPortDriver *ftdipp);
+static void _stopS(USBHFTDIPortDriver *ftdipp);
static void _ftdi_unload(usbh_baseclassdriver_t *drv) {
osalDbgCheck(drv != NULL);
USBHFTDIDriver *const ftdip = (USBHFTDIDriver *)drv;
@@ -219,7 +218,10 @@ static void _ftdi_unload(usbh_baseclassdriver_t *drv) {
osalMutexLock(&ftdip->mtx);
while (ftdipp) {
- _stop(ftdipp);
+ osalSysLock();
+ _stopS(ftdipp);
+ osalOsRescheduleS();
+ osalSysUnlock();
ftdipp = ftdipp->next;
}
@@ -314,17 +316,17 @@ static usbh_urbstatus_t _ftdi_port_control(USBHFTDIPortDriver *ftdipp,
uint8_t *buff) {
static const uint8_t bmRequestType[] = {
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //0 FTDI_COMMAND_RESET
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //1 FTDI_COMMAND_MODEMCTRL
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //2 FTDI_COMMAND_SETFLOW
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //3 FTDI_COMMAND_SETBAUD
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //4 FTDI_COMMAND_SETDATA
+ USBH_REQTYPE_TYPE_VENDOR | USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_RECIP_DEVICE, //0 FTDI_COMMAND_RESET
+ USBH_REQTYPE_TYPE_VENDOR | USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_RECIP_DEVICE, //1 FTDI_COMMAND_MODEMCTRL
+ USBH_REQTYPE_TYPE_VENDOR | USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_RECIP_DEVICE, //2 FTDI_COMMAND_SETFLOW
+ USBH_REQTYPE_TYPE_VENDOR | USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_RECIP_DEVICE, //3 FTDI_COMMAND_SETBAUD
+ USBH_REQTYPE_TYPE_VENDOR | USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_RECIP_DEVICE, //4 FTDI_COMMAND_SETDATA
};
osalDbgCheck(bRequest < sizeof_array(bmRequestType));
osalDbgCheck(bRequest != 1);
- const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = {
+ USBH_DEFINE_BUFFER(const usbh_control_request_t req) = {
bmRequestType[bRequest],
bRequest,
wValue,
@@ -387,8 +389,8 @@ static usbh_urbstatus_t _set_baudrate(USBHFTDIPortDriver *ftdipp, uint32_t baudr
if (ftdipp->ftdip->dev->basicConfigDesc.bNumInterfaces > 1)
wIndex = (wIndex << 8) | (ftdipp->ifnum + 1);
- const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = {
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE,
+ USBH_DEFINE_BUFFER(const usbh_control_request_t req) = {
+ USBH_REQTYPE_TYPE_VENDOR | USBH_REQTYPE_DIR_OUT | USBH_REQTYPE_RECIP_DEVICE,
FTDI_COMMAND_SETBAUD,
wValue,
wIndex,
@@ -626,29 +628,27 @@ static const struct FTDIPortDriverVMT async_channel_vmt = {
};
-static void _stop(USBHFTDIPortDriver *ftdipp) {
- osalSysLock();
+static void _stopS(USBHFTDIPortDriver *ftdipp) {
+ if (ftdipp->state != USBHFTDIP_STATE_READY)
+ return;
chVTResetI(&ftdipp->vt);
usbhEPCloseS(&ftdipp->epin);
usbhEPCloseS(&ftdipp->epout);
chThdDequeueAllI(&ftdipp->iq_waiting, Q_RESET);
chThdDequeueAllI(&ftdipp->oq_waiting, Q_RESET);
- osalOsRescheduleS();
ftdipp->state = USBHFTDIP_STATE_ACTIVE;
- osalSysUnlock();
}
void usbhftdipStop(USBHFTDIPortDriver *ftdipp) {
osalDbgCheck((ftdipp->state == USBHFTDIP_STATE_ACTIVE)
|| (ftdipp->state == USBHFTDIP_STATE_READY));
- if (ftdipp->state == USBHFTDIP_STATE_ACTIVE) {
- return;
- }
-
- osalMutexLock(&ftdipp->ftdip->mtx);
- _stop(ftdipp);
- osalMutexUnlock(&ftdipp->ftdip->mtx);
+ osalSysLock();
+ chMtxLockS(&ftdipp->ftdip->mtx);
+ _stopS(ftdipp);
+ chMtxUnlockS(&ftdipp->ftdip->mtx);
+ osalOsRescheduleS();
+ osalSysUnlock();
}
void usbhftdipStart(USBHFTDIPortDriver *ftdipp, const USBHFTDIPortConfig *config) {
@@ -714,4 +714,14 @@ void usbhftdipObjectInit(USBHFTDIPortDriver *ftdipp) {
ftdipp->state = USBHFTDIP_STATE_STOP;
}
+void usbhftdiInit(void) {
+ uint8_t i;
+ for (i = 0; i < HAL_USBHFTDI_MAX_INSTANCES; i++) {
+ usbhftdiObjectInit(&USBHFTDID[i]);
+ }
+ for (i = 0; i < HAL_USBHFTDI_MAX_PORTS; i++) {
+ usbhftdipObjectInit(&FTDIPD[i]);
+ }
+}
+
#endif
diff --git a/os/hal/src/usbh/hal_usbh_hid.c b/os/hal/src/usbh/hal_usbh_hid.c
new file mode 100644
index 0000000..e98dff7
--- /dev/null
+++ b/os/hal/src/usbh/hal_usbh_hid.c
@@ -0,0 +1,322 @@
+/*
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+#include "hal.h"
+
+#if HAL_USBH_USE_HID
+
+#if !HAL_USE_USBH
+#error "USBHHID needs USBH"
+#endif
+
+#include <string.h>
+#include "usbh/dev/hid.h"
+#include "usbh/internal.h"
+
+#if USBHHID_DEBUG_ENABLE_TRACE
+#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
+#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
+#else
+#define udbgf(f, ...) do {} while(0)
+#define udbg(f, ...) do {} while(0)
+#endif
+
+#if USBHHID_DEBUG_ENABLE_INFO
+#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
+#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
+#else
+#define uinfof(f, ...) do {} while(0)
+#define uinfo(f, ...) do {} while(0)
+#endif
+
+#if USBHHID_DEBUG_ENABLE_WARNINGS
+#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
+#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
+#else
+#define uwarnf(f, ...) do {} while(0)
+#define uwarn(f, ...) do {} while(0)
+#endif
+
+#if USBHHID_DEBUG_ENABLE_ERRORS
+#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
+#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
+#else
+#define uerrf(f, ...) do {} while(0)
+#define uerr(f, ...) do {} while(0)
+#endif
+
+
+
+#define USBH_HID_REQ_GET_REPORT 0x01
+#define USBH_HID_REQ_GET_IDLE 0x02
+#define USBH_HID_REQ_GET_PROTOCOL 0x03
+#define USBH_HID_REQ_SET_REPORT 0x09
+#define USBH_HID_REQ_SET_IDLE 0x0A
+#define USBH_HID_REQ_SET_PROTOCOL 0x0B
+
+/*===========================================================================*/
+/* USB Class driver loader for MSD */
+/*===========================================================================*/
+
+USBHHIDDriver USBHHIDD[HAL_USBHHID_MAX_INSTANCES];
+
+static usbh_baseclassdriver_t *_hid_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem);
+static void _hid_unload(usbh_baseclassdriver_t *drv);
+
+static const usbh_classdriver_vmt_t class_driver_vmt = {
+ _hid_load,
+ _hid_unload
+};
+
+const usbh_classdriverinfo_t usbhhidClassDriverInfo = {
+ 0x03, -1, -1, "HID", &class_driver_vmt
+};
+
+static usbh_baseclassdriver_t *_hid_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
+ int i;
+ USBHHIDDriver *hidp;
+
+ if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE))
+ return NULL;
+
+ const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t *)descriptor;
+
+ if ((ifdesc->bAlternateSetting != 0)
+ || (ifdesc->bNumEndpoints < 1)) {
+ return NULL;
+ }
+
+
+ /* alloc driver */
+ for (i = 0; i < HAL_USBHHID_MAX_INSTANCES; i++) {
+ if (USBHHIDD[i].dev == NULL) {
+ hidp = &USBHHIDD[i];
+ goto alloc_ok;
+ }
+ }
+
+ uwarn("Can't alloc HID driver");
+
+ /* can't alloc */
+ return NULL;
+
+alloc_ok:
+ /* initialize the driver's variables */
+ hidp->epin.status = USBH_EPSTATUS_UNINITIALIZED;
+#if HAL_USBHHID_USE_INTERRUPT_OUT
+ hidp->epout.status = USBH_EPSTATUS_UNINITIALIZED;
+#endif
+ hidp->ifnum = ifdesc->bInterfaceNumber;
+ usbhEPSetName(&dev->ctrl, "HID[CTRL]");
+
+ /* parse the configuration descriptor */
+ if_iterator_t iif;
+ generic_iterator_t iep;
+ iif.iad = 0;
+ iif.curr = descriptor;
+ iif.rem = rem;
+ for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) {
+ const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
+ if ((epdesc->bEndpointAddress & 0x80) && (epdesc->bmAttributes == USBH_EPTYPE_INT)) {
+ uinfof("INT IN endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
+ usbhEPObjectInit(&hidp->epin, dev, epdesc);
+ usbhEPSetName(&hidp->epin, "HID[IIN ]");
+#if HAL_USBHHID_USE_INTERRUPT_OUT
+ } else if (((epdesc->bEndpointAddress & 0x80) == 0)
+ && (epdesc->bmAttributes == USBH_EPTYPE_INT)) {
+ uinfof("INT OUT endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
+ usbhEPObjectInit(&hidp->epout, dev, epdesc);
+ usbhEPSetName(&hidp->epout, "HID[IOUT]");
+#endif
+ } else {
+ uinfof("unsupported endpoint found: bEndpointAddress=%02x, bmAttributes=%02x",
+ epdesc->bEndpointAddress, epdesc->bmAttributes);
+ }
+ }
+ if (hidp->epin.status != USBH_EPSTATUS_CLOSED) {
+ goto deinit;
+ }
+
+ if (ifdesc->bInterfaceSubClass != 0x01) {
+ hidp->type = USBHHID_DEVTYPE_GENERIC;
+ uinfof("HID: bInterfaceSubClass=%02x, generic HID", ifdesc->bInterfaceSubClass);
+ if (ifdesc->bInterfaceSubClass != 0x00) {
+ uinfof("HID: bInterfaceSubClass=%02x is an invalid bInterfaceSubClass value",
+ ifdesc->bInterfaceSubClass);
+ }
+ } else if (ifdesc->bInterfaceProtocol == 0x01) {
+ hidp->type = USBHHID_DEVTYPE_BOOT_KEYBOARD;
+ uinfo("HID: BOOT protocol keyboard found");
+ } else if (ifdesc->bInterfaceProtocol == 0x02) {
+ hidp->type = USBHHID_DEVTYPE_BOOT_MOUSE;
+ uinfo("HID: BOOT protocol mouse found");
+ } else {
+ uerrf("HID: bInterfaceProtocol=%02x is an invalid boot protocol, abort",
+ ifdesc->bInterfaceProtocol);
+ goto deinit;
+ }
+
+ hidp->state = USBHHID_STATE_ACTIVE;
+
+ return (usbh_baseclassdriver_t *)hidp;
+
+deinit:
+ /* Here, the enpoints are closed, and the driver is unlinked */
+ return NULL;
+}
+
+static void _hid_unload(usbh_baseclassdriver_t *drv) {
+ (void)drv;
+}
+
+static void _in_cb(usbh_urb_t *urb) {
+ USBHHIDDriver *const hidp = (USBHHIDDriver *)urb->userData;
+ switch (urb->status) {
+ case USBH_URBSTATUS_OK:
+ if (hidp->config->cb_report) {
+ hidp->config->cb_report(hidp, urb->actualLength);
+ }
+ break;
+ case USBH_URBSTATUS_DISCONNECTED:
+ uwarn("HID: URB IN disconnected");
+
+ return;
+ case USBH_URBSTATUS_TIMEOUT:
+ //no data
+ break;
+ default:
+ uerrf("HID: URB IN status unexpected = %d", urb->status);
+ break;
+ }
+ usbhURBObjectResetI(&hidp->in_urb);
+ usbhURBSubmitI(&hidp->in_urb);
+}
+
+void usbhhidStart(USBHHIDDriver *hidp, const USBHHIDConfig *cfg) {
+ osalDbgCheck(hidp && cfg);
+ osalDbgCheck(cfg->report_buffer && (cfg->protocol <= USBHHID_PROTOCOL_REPORT));
+ osalDbgCheck((hidp->state == USBHHID_STATE_ACTIVE)
+ || (hidp->state == USBHHID_STATE_READY));
+
+ if (hidp->state == USBHHID_STATE_READY)
+ return;
+
+ hidp->config = cfg;
+
+ /* init the URBs */
+ usbhURBObjectInit(&hidp->in_urb, &hidp->epin, _in_cb, hidp,
+ cfg->report_buffer, cfg->report_len);
+
+ /* open the int IN/OUT endpoints */
+ usbhEPOpen(&hidp->epin);
+#if HAL_USBHHID_USE_INTERRUPT_OUT
+ if (hidp->epout.status == USBH_EPSTATUS_CLOSED) {
+ usbhEPOpen(&hidp->epout);
+ }
+#endif
+
+ usbhhidSetProtocol(hidp, cfg->protocol);
+
+ osalSysLock();
+ usbhURBSubmitI(&hidp->in_urb);
+ osalSysUnlock();
+
+ hidp->state = USBHHID_STATE_READY;
+}
+
+void usbhhidStop(USBHHIDDriver *hidp) {
+ osalDbgCheck((hidp->state == USBHHID_STATE_ACTIVE)
+ || (hidp->state == USBHHID_STATE_READY));
+
+ if (hidp->state != USBHHID_STATE_READY)
+ return;
+
+ osalSysLock();
+ usbhEPCloseS(&hidp->epin);
+#if HAL_USBHHID_USE_INTERRUPT_OUT
+ if (hidp->epout.status != USBH_EPSTATUS_UNINITIALIZED) {
+ usbhEPCloseS(&hidp->epout);
+ }
+#endif
+ hidp->state = USBHHID_STATE_ACTIVE;
+ osalSysUnlock();
+}
+
+usbh_urbstatus_t usbhhidGetReport(USBHHIDDriver *hidp,
+ uint8_t report_id, usbhhid_reporttype_t report_type,
+ void *data, uint16_t len) {
+ osalDbgCheck(hidp);
+ osalDbgAssert((uint8_t)report_type <= USBHHID_REPORTTYPE_FEATURE, "wrong report type");
+ return usbhControlRequest(hidp->dev,
+ USBH_REQTYPE_CLASSIN(USBH_REQTYPE_RECIP_INTERFACE), USBH_HID_REQ_GET_REPORT,
+ ((uint8_t)report_type << 8) | report_id, hidp->ifnum, len, data);
+}
+
+usbh_urbstatus_t usbhhidSetReport(USBHHIDDriver *hidp,
+ uint8_t report_id, usbhhid_reporttype_t report_type,
+ const void *data, uint16_t len) {
+ osalDbgCheck(hidp);
+ osalDbgAssert((uint8_t)report_type <= USBHHID_REPORTTYPE_FEATURE, "wrong report type");
+ return usbhControlRequest(hidp->dev,
+ USBH_REQTYPE_CLASSOUT(USBH_REQTYPE_RECIP_INTERFACE), USBH_HID_REQ_SET_REPORT,
+ ((uint8_t)report_type << 8) | report_id, hidp->ifnum, len, (void *)data);
+}
+
+usbh_urbstatus_t usbhhidGetIdle(USBHHIDDriver *hidp, uint8_t report_id, uint8_t *duration) {
+ osalDbgCheck(hidp);
+ return usbhControlRequest(hidp->dev,
+ USBH_REQTYPE_CLASSIN(USBH_REQTYPE_RECIP_INTERFACE), USBH_HID_REQ_GET_IDLE,
+ report_id, hidp->ifnum, 1, duration);
+}
+
+usbh_urbstatus_t usbhhidSetIdle(USBHHIDDriver *hidp, uint8_t report_id, uint8_t duration) {
+ osalDbgCheck(hidp);
+ return usbhControlRequest(hidp->dev,
+ USBH_REQTYPE_CLASSOUT(USBH_REQTYPE_RECIP_INTERFACE), USBH_HID_REQ_SET_IDLE,
+ (duration << 8) | report_id, hidp->ifnum, 0, NULL);
+}
+
+usbh_urbstatus_t usbhhidGetProtocol(USBHHIDDriver *hidp, uint8_t *protocol) {
+ osalDbgCheck(hidp);
+ return usbhControlRequest(hidp->dev,
+ USBH_REQTYPE_CLASSIN(USBH_REQTYPE_RECIP_INTERFACE), USBH_HID_REQ_GET_PROTOCOL,
+ 0, hidp->ifnum, 1, protocol);
+}
+
+usbh_urbstatus_t usbhhidSetProtocol(USBHHIDDriver *hidp, uint8_t protocol) {
+ osalDbgCheck(hidp);
+ osalDbgAssert(protocol <= 1, "invalid protocol");
+ return usbhControlRequest(hidp->dev,
+ USBH_REQTYPE_CLASSOUT(USBH_REQTYPE_RECIP_INTERFACE), USBH_HID_REQ_SET_PROTOCOL,
+ protocol, hidp->ifnum, 0, NULL);
+}
+
+void usbhhidObjectInit(USBHHIDDriver *hidp) {
+ osalDbgCheck(hidp != NULL);
+ memset(hidp, 0, sizeof(*hidp));
+ hidp->info = &usbhhidClassDriverInfo;
+ hidp->state = USBHHID_STATE_STOP;
+}
+
+void usbhhidInit(void) {
+ uint8_t i;
+ for (i = 0; i < HAL_USBHHID_MAX_INSTANCES; i++) {
+ usbhhidObjectInit(&USBHHIDD[i]);
+ }
+}
+
+#endif
diff --git a/os/hal/src/usbh/hal_usbh_hub.c b/os/hal/src/usbh/hal_usbh_hub.c
index 56257b2..3a84175 100644
--- a/os/hal/src/usbh/hal_usbh_hub.c
+++ b/os/hal/src/usbh/hal_usbh_hub.c
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,10 +15,7 @@
limitations under the License.
*/
-#include <string.h>
#include "hal.h"
-#include "hal_usbh.h"
-#include "usbh/internal.h"
#if HAL_USBH_USE_HUB
@@ -28,6 +25,7 @@
#include <string.h>
#include "usbh/dev/hub.h"
+#include "usbh/internal.h"
#if USBHHUB_DEBUG_ENABLE_TRACE
#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
@@ -63,7 +61,7 @@
USBHHubDriver USBHHUBD[HAL_USBHHUB_MAX_INSTANCES];
-usbh_port_t USBHPorts[HAL_USBHHUB_MAX_PORTS];
+static usbh_port_t USBHPorts[HAL_USBHHUB_MAX_PORTS];
static usbh_baseclassdriver_t *hub_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem);
static void hub_unload(usbh_baseclassdriver_t *drv);
@@ -200,7 +198,7 @@ alloc_ok:
/* read Hub descriptor */
uinfo("Read Hub descriptor");
if (usbhhubControlRequest(dev->host, hubdp,
- USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE,
+ USBH_REQTYPE_DIR_IN | USBH_REQTYPE_TYPE_CLASS | USBH_REQTYPE_RECIP_DEVICE,
USBH_REQ_GET_DESCRIPTOR,
(USBH_DT_HUB << 8), 0, sizeof(hubdp->hubDesc),
(uint8_t *)&hubdp->hubDesc) != USBH_URBSTATUS_OK) {
@@ -290,9 +288,18 @@ void usbhhubObjectInit(USBHHubDriver *hubdp) {
memset(hubdp, 0, sizeof(*hubdp));
hubdp->info = &usbhhubClassDriverInfo;
}
+
+void usbhhubInit(void) {
+ uint8_t i;
+ for (i = 0; i < HAL_USBHHUB_MAX_INSTANCES; i++) {
+ usbhhubObjectInit(&USBHHUBD[i]);
+ }
+}
+
#else
#if HAL_USE_USBH
+#include <string.h>
void _usbhub_port_object_init(usbh_port_t *port, USBHDriver *usbh, uint8_t number) {
memset(port, 0, sizeof(*port));
port->number = number;
diff --git a/os/hal/src/usbh/hal_usbh_msd.c b/os/hal/src/usbh/hal_usbh_msd.c
index 7a4f826..121e730 100644
--- a/os/hal/src/usbh/hal_usbh_msd.c
+++ b/os/hal/src/usbh/hal_usbh_msd.c
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
*/
#include "hal.h"
-#include "hal_usbh.h"
#if HAL_USBH_USE_MSD
@@ -91,8 +90,8 @@ const usbh_classdriverinfo_t usbhmsdClassDriverInfo = {
static usbh_baseclassdriver_t *_msd_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
int i;
USBHMassStorageDriver *msdp;
- uint8_t luns; // should declare it here to eliminate 'control bypass initialization' warning
- usbh_urbstatus_t stat; // should declare it here to eliminate 'control bypass initialization' warning
+ uint8_t luns;
+ usbh_urbstatus_t stat;
if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE))
return NULL;
@@ -157,10 +156,10 @@ alloc_ok:
/* read the number of LUNs */
uinfo("Reading Max LUN:");
- USBH_DEFINE_BUFFER(uint8_t, buff[4]);
+ USBH_DEFINE_BUFFER(uint8_t buff[4]);
stat = usbhControlRequest(dev,
- USBH_CLASSIN(USBH_REQTYPE_INTERFACE, MSD_GET_MAX_LUN, 0, msdp->ifnum),
- 1, buff);
+ USBH_REQTYPE_CLASSIN(USBH_REQTYPE_RECIP_INTERFACE),
+ MSD_GET_MAX_LUN, 0, msdp->ifnum, 1, buff);
if (stat == USBH_URBSTATUS_OK) {
msdp->max_lun = buff[0] + 1;
uinfof("\tmax_lun = %d", msdp->max_lun);
@@ -194,7 +193,9 @@ alloc_ok:
osalSysUnlock();
/* connect the LUN (TODO: review if it's best to leave the LUN disconnected) */
+ msdp->dev = dev;
usbhmsdLUNConnect(&MSBLKD[i]);
+ msdp->dev = NULL;
luns--;
}
}
@@ -240,7 +241,7 @@ static void _msd_unload(usbh_baseclassdriver_t *drv) {
/* USB Bulk Only Transport SCSI Command block wrapper */
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint32_t dCBWSignature;
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
@@ -253,9 +254,8 @@ PACKED_STRUCT {
#define MSD_CBWFLAGS_D2H 0x80
#define MSD_CBWFLAGS_H2D 0x00
-
/* USB Bulk Only Transport SCSI Command status wrapper */
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint32_t dCSWSignature;
uint32_t dCSWTag;
uint32_t dCSWDataResidue;
@@ -263,32 +263,172 @@ PACKED_STRUCT {
} msd_csw_t;
#define MSD_CSW_SIGNATURE 0x53425355
-
-typedef union {
- msd_cbw_t cbw;
- msd_csw_t csw;
+typedef struct {
+ msd_cbw_t *cbw;
+ uint8_t csw_status;
+ uint32_t data_processed;
} msd_transaction_t;
typedef enum {
- MSD_TRANSACTIONRESULT_OK,
- MSD_TRANSACTIONRESULT_DISCONNECTED,
- MSD_TRANSACTIONRESULT_STALL,
- MSD_TRANSACTIONRESULT_BUS_ERROR,
- MSD_TRANSACTIONRESULT_SYNC_ERROR
-} msd_transaction_result_t;
+ MSD_BOTRESULT_OK,
+ MSD_BOTRESULT_DISCONNECTED,
+ MSD_BOTRESULT_ERROR
+} msd_bot_result_t;
typedef enum {
- MSD_COMMANDRESULT_PASSED = 0,
- MSD_COMMANDRESULT_FAILED = 1,
- MSD_COMMANDRESULT_PHASE_ERROR = 2
-} msd_command_result_t;
-
-typedef struct {
- msd_transaction_result_t tres;
- msd_command_result_t cres;
+ MSD_RESULT_OK = MSD_BOTRESULT_OK,
+ MSD_RESULT_DISCONNECTED = MSD_BOTRESULT_DISCONNECTED,
+ MSD_RESULT_TRANSPORT_ERROR = MSD_BOTRESULT_ERROR,
+ MSD_RESULT_FAILED
} msd_result_t;
+#define CSW_STATUS_PASSED 0
+#define CSW_STATUS_FAILED 1
+#define CSW_STATUS_PHASE_ERROR 2
+
+static bool _msd_bot_reset(USBHMassStorageDriver *msdp) {
+
+ usbh_urbstatus_t res;
+ res = usbhControlRequest(msdp->dev,
+ USBH_REQTYPE_CLASSOUT(USBH_REQTYPE_RECIP_INTERFACE),
+ 0xFF, 0, msdp->ifnum, 0, NULL);
+ if (res != USBH_URBSTATUS_OK) {
+ return FALSE;
+ }
+
+ osalThreadSleepMilliseconds(100);
+
+ return usbhEPReset(&msdp->epin) && usbhEPReset(&msdp->epout);
+}
+
+static msd_bot_result_t _msd_bot_transaction(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp, void *data) {
+
+ uint32_t data_actual_len, actual_len;
+ usbh_urbstatus_t status;
+ USBH_DEFINE_BUFFER(msd_csw_t csw);
+
+ tran->cbw->bCBWLUN = (uint8_t)(lunp - &lunp->msdp->luns[0]);
+ tran->cbw->dCBWSignature = MSD_CBW_SIGNATURE;
+ tran->cbw->dCBWTag = ++lunp->msdp->tag;
+ tran->data_processed = 0;
+
+ /* control phase */
+ status = usbhBulkTransfer(&lunp->msdp->epout, tran->cbw,
+ sizeof(*tran->cbw), &actual_len, MS2ST(1000));
+
+ if (status == USBH_URBSTATUS_CANCELLED) {
+ uerr("\tMSD: Control phase: USBH_URBSTATUS_CANCELLED");
+ return MSD_BOTRESULT_DISCONNECTED;
+ }
+
+ if ((status != USBH_URBSTATUS_OK) || (actual_len != sizeof(*tran->cbw))) {
+ uerrf("\tMSD: Control phase: status = %d (!= OK), actual_len = %d (expected to send %d)",
+ status, actual_len, sizeof(*tran->cbw));
+ _msd_bot_reset(lunp->msdp);
+ return MSD_BOTRESULT_ERROR;
+ }
+
+
+ /* data phase */
+ data_actual_len = 0;
+ if (tran->cbw->dCBWDataTransferLength) {
+ usbh_ep_t *const ep = tran->cbw->bmCBWFlags & MSD_CBWFLAGS_D2H ? &lunp->msdp->epin : &lunp->msdp->epout;
+ status = usbhBulkTransfer(
+ ep,
+ data,
+ tran->cbw->dCBWDataTransferLength,
+ &data_actual_len, MS2ST(20000));
+
+ if (status == USBH_URBSTATUS_CANCELLED) {
+ uerr("\tMSD: Data phase: USBH_URBSTATUS_CANCELLED");
+ return MSD_BOTRESULT_DISCONNECTED;
+ }
+
+ if (status == USBH_URBSTATUS_STALL) {
+ uerrf("\tMSD: Data phase: USBH_URBSTATUS_STALL, clear halt");
+ status = usbhEPReset(ep);
+ }
+
+ if (status != USBH_URBSTATUS_OK) {
+ uerrf("\tMSD: Data phase: status = %d (!= OK), resetting", status);
+ _msd_bot_reset(lunp->msdp);
+ return MSD_BOTRESULT_ERROR;
+ }
+ }
+
+
+ /* status phase */
+ status = usbhBulkTransfer(&lunp->msdp->epin, &csw,
+ sizeof(csw), &actual_len, MS2ST(1000));
+
+ if (status == USBH_URBSTATUS_STALL) {
+ uwarn("\tMSD: Status phase: USBH_URBSTATUS_STALL, clear halt and retry");
+
+ status = usbhEPReset(&lunp->msdp->epin);
+
+ if (status == USBH_URBSTATUS_OK) {
+ status = usbhBulkTransfer(&lunp->msdp->epin, &csw,
+ sizeof(csw), &actual_len, MS2ST(1000));
+ }
+ }
+
+ if (status == USBH_URBSTATUS_CANCELLED) {
+ uerr("\tMSD: Status phase: USBH_URBSTATUS_CANCELLED");
+ return MSD_BOTRESULT_DISCONNECTED;
+ }
+
+ if (status != USBH_URBSTATUS_OK) {
+ uerrf("\tMSD: Status phase: status = %d (!= OK), resetting", status);
+ _msd_bot_reset(lunp->msdp);
+ return MSD_BOTRESULT_ERROR;
+ }
+
+ /* validate CSW */
+ if ((actual_len != sizeof(csw))
+ || (csw.dCSWSignature != MSD_CSW_SIGNATURE)
+ || (csw.dCSWTag != lunp->msdp->tag)
+ || (csw.bCSWStatus >= CSW_STATUS_PHASE_ERROR)) {
+ /* CSW is not valid */
+ uerrf("\tMSD: Status phase: Invalid CSW: len=%d, dCSWSignature=%x, dCSWTag=%x (expected %x), bCSWStatus=%d, resetting",
+ actual_len,
+ csw.dCSWSignature,
+ csw.dCSWTag,
+ lunp->msdp->tag,
+ csw.bCSWStatus);
+ _msd_bot_reset(lunp->msdp);
+ return MSD_BOTRESULT_ERROR;
+ }
+
+ /* check if CSW is meaningful */
+ if ((csw.bCSWStatus != CSW_STATUS_PHASE_ERROR)
+ && (csw.dCSWDataResidue > tran->cbw->dCBWDataTransferLength)) {
+ /* CSW is not meaningful */
+ uerrf("\tMSD: Status phase: CSW not meaningful: bCSWStatus=%d, dCSWDataResidue=%u, dCBWDataTransferLength=%u, resetting",
+ csw.bCSWStatus,
+ csw.dCSWDataResidue,
+ tran->cbw->dCBWDataTransferLength);
+ _msd_bot_reset(lunp->msdp);
+ return MSD_BOTRESULT_ERROR;
+ }
+
+ if (csw.bCSWStatus == CSW_STATUS_PHASE_ERROR) {
+ uerr("\tMSD: Status phase: Phase error, resetting");
+ _msd_bot_reset(lunp->msdp);
+ return MSD_BOTRESULT_ERROR;
+ }
+
+ tran->data_processed = tran->cbw->dCBWDataTransferLength - csw.dCSWDataResidue;
+ if (data_actual_len < tran->data_processed) {
+ tran->data_processed = data_actual_len;
+ }
+
+ tran->csw_status = csw.bCSWStatus;
+
+ return MSD_BOTRESULT_OK;
+}
+
+
/* ----------------------------------------------------- */
/* SCSI Commands */
/* ----------------------------------------------------- */
@@ -299,7 +439,7 @@ typedef struct {
/* Request sense */
#define SCSI_CMD_REQUEST_SENSE 0x03
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t byte[18];
} scsi_sense_response_t;
@@ -333,7 +473,7 @@ PACKED_STRUCT {
/* Inquiry */
#define SCSI_CMD_INQUIRY 0x12
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t peripheral;
uint8_t removable;
uint8_t version;
@@ -349,14 +489,14 @@ PACKED_STRUCT {
/* Read Capacity 10 */
#define SCSI_CMD_READ_CAPACITY_10 0x25
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint32_t last_block_addr;
uint32_t block_size;
} scsi_readcapacity10_response_t;
/* Start/Stop Unit */
#define SCSI_CMD_START_STOP_UNIT 0x1B
-PACKED_STRUCT {
+typedef PACKED_STRUCT {
uint8_t op_code;
uint8_t lun_immed;
uint8_t res1;
@@ -368,216 +508,180 @@ PACKED_STRUCT {
/* test unit ready */
#define SCSI_CMD_TEST_UNIT_READY 0x00
-/* Other commands, TODO: use or remove them
-#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
-#define SCSI_CMD_VERIFY_10 0x2F
-#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
-#define SCSI_CMD_MODE_SENSE_6 0x1A
-*/
-
-static inline void _prepare_cbw(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp) {
- tran->cbw.bCBWLUN = (uint8_t)(lunp - &lunp->msdp->luns[0]);
- memset(&tran->cbw.CBWCB, 0, sizeof(tran->cbw.CBWCB));
-}
-
-static msd_transaction_result_t _msd_transaction(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp, void *data) {
-
- uint32_t actual_len;
- usbh_urbstatus_t status;
-
- tran->cbw.dCBWSignature = MSD_CBW_SIGNATURE;
- tran->cbw.dCBWTag = ++lunp->msdp->tag;
+static msd_result_t scsi_requestsense(USBHMassStorageLUNDriver *lunp, scsi_sense_response_t *resp);
- /* control phase */
- status = usbhBulkTransfer(&lunp->msdp->epout, &tran->cbw,
- sizeof(tran->cbw), &actual_len, MS2ST(1000));
+static msd_result_t _scsi_perform_transaction(USBHMassStorageLUNDriver *lunp,
+ msd_transaction_t *transaction, void *data) {
- if (status == USBH_URBSTATUS_CANCELLED) {
- uerr("\tMSD: Control phase: USBH_URBSTATUS_CANCELLED");
- return MSD_TRANSACTIONRESULT_DISCONNECTED;
- } else if (status == USBH_URBSTATUS_STALL) {
- uerr("\tMSD: Control phase: USBH_URBSTATUS_STALL");
- return MSD_TRANSACTIONRESULT_STALL;
- } else if (status != USBH_URBSTATUS_OK) {
- uerrf("\tMSD: Control phase: status = %d, != OK", status);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- } else if (actual_len != sizeof(tran->cbw)) {
- uerrf("\tMSD: Control phase: wrong actual_len = %d", actual_len);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
+ msd_bot_result_t res;
+ res = _msd_bot_transaction(transaction, lunp, data);
+ if (res != MSD_BOTRESULT_OK) {
+ return (msd_result_t)res;
}
-
- /* data phase */
- if (tran->cbw.dCBWDataTransferLength) {
- status = usbhBulkTransfer(
- tran->cbw.bmCBWFlags & MSD_CBWFLAGS_D2H ? &lunp->msdp->epin : &lunp->msdp->epout,
- data,
- tran->cbw.dCBWDataTransferLength,
- &actual_len, MS2ST(20000));
-
- if (status == USBH_URBSTATUS_CANCELLED) {
- uerr("\tMSD: Data phase: USBH_URBSTATUS_CANCELLED");
- return MSD_TRANSACTIONRESULT_DISCONNECTED;
- } else if (status == USBH_URBSTATUS_STALL) {
- uerr("\tMSD: Data phase: USBH_URBSTATUS_STALL");
- return MSD_TRANSACTIONRESULT_STALL;
- } else if (status != USBH_URBSTATUS_OK) {
- uerrf("\tMSD: Data phase: status = %d, != OK", status);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- } else if (actual_len != tran->cbw.dCBWDataTransferLength) {
- uerrf("\tMSD: Data phase: wrong actual_len = %d", actual_len);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
+ if (transaction->csw_status == CSW_STATUS_FAILED) {
+ if (transaction->cbw->CBWCB[0] != SCSI_CMD_REQUEST_SENSE) {
+ /* do auto-sense (except for SCSI_CMD_REQUEST_SENSE!) */
+ uwarn("\tMSD: Command failed, auto-sense");
+ USBH_DEFINE_BUFFER(scsi_sense_response_t sense);
+ if (scsi_requestsense(lunp, &sense) == MSD_RESULT_OK) {
+ uwarnf("\tMSD: REQUEST SENSE: Sense key=%x, ASC=%02x, ASCQ=%02x",
+ sense.byte[2] & 0xf, sense.byte[12], sense.byte[13]);
+ }
}
+ return MSD_RESULT_FAILED;
}
-
- /* status phase */
- status = usbhBulkTransfer(&lunp->msdp->epin, &tran->csw,
- sizeof(tran->csw), &actual_len, MS2ST(1000));
-
- if (status == USBH_URBSTATUS_CANCELLED) {
- uerr("\tMSD: Status phase: USBH_URBSTATUS_CANCELLED");
- return MSD_TRANSACTIONRESULT_DISCONNECTED;
- } else if (status == USBH_URBSTATUS_STALL) {
- uerr("\tMSD: Status phase: USBH_URBSTATUS_STALL");
- return MSD_TRANSACTIONRESULT_STALL;
- } else if (status != USBH_URBSTATUS_OK) {
- uerrf("\tMSD: Status phase: status = %d, != OK", status);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- } else if (actual_len != sizeof(tran->csw)) {
- uerrf("\tMSD: Status phase: wrong actual_len = %d", actual_len);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- } else if (tran->csw.dCSWSignature != MSD_CSW_SIGNATURE) {
- uerr("\tMSD: Status phase: wrong signature");
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- } else if (tran->csw.dCSWTag != lunp->msdp->tag) {
- uerrf("\tMSD: Status phase: wrong tag (expected %d, got %d)",
- lunp->msdp->tag, tran->csw.dCSWTag);
- return MSD_TRANSACTIONRESULT_SYNC_ERROR;
- }
-
- if (tran->csw.dCSWDataResidue) {
- uwarnf("\tMSD: Residue=%d", tran->csw.dCSWDataResidue);
- }
-
- return MSD_TRANSACTIONRESULT_OK;
+ return MSD_RESULT_OK;
}
-
static msd_result_t scsi_inquiry(USBHMassStorageLUNDriver *lunp, scsi_inquiry_response_t *resp) {
+ USBH_DEFINE_BUFFER(msd_cbw_t cbw);
msd_transaction_t transaction;
msd_result_t res;
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = sizeof(scsi_inquiry_response_t);
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
- transaction.cbw.bCBWCBLength = 6;
- transaction.cbw.CBWCB[0] = SCSI_CMD_INQUIRY;
- transaction.cbw.CBWCB[4] = sizeof(scsi_inquiry_response_t);
-
- res.tres = _msd_transaction(&transaction, lunp, resp);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
+ memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
+ cbw.dCBWDataTransferLength = sizeof(scsi_inquiry_response_t);
+ cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
+ cbw.bCBWCBLength = 6;
+ cbw.CBWCB[0] = SCSI_CMD_INQUIRY;
+ cbw.CBWCB[4] = sizeof(scsi_inquiry_response_t);
+ transaction.cbw = &cbw;
+
+ res = _scsi_perform_transaction(lunp, &transaction, resp);
+ if (res == MSD_RESULT_OK) {
+ //transaction is OK; check length
+ if (transaction.data_processed < cbw.dCBWDataTransferLength) {
+ res = MSD_RESULT_TRANSPORT_ERROR;
+ }
}
+
return res;
}
static msd_result_t scsi_requestsense(USBHMassStorageLUNDriver *lunp, scsi_sense_response_t *resp) {
+ USBH_DEFINE_BUFFER(msd_cbw_t cbw);
msd_transaction_t transaction;
msd_result_t res;
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = sizeof(scsi_sense_response_t);
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
- transaction.cbw.bCBWCBLength = 12;
- transaction.cbw.CBWCB[0] = SCSI_CMD_REQUEST_SENSE;
- transaction.cbw.CBWCB[4] = sizeof(scsi_sense_response_t);
-
- res.tres = _msd_transaction(&transaction, lunp, resp);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
+ memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
+ cbw.dCBWDataTransferLength = sizeof(scsi_sense_response_t);
+ cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
+ cbw.bCBWCBLength = 12;
+ cbw.CBWCB[0] = SCSI_CMD_REQUEST_SENSE;
+ cbw.CBWCB[4] = sizeof(scsi_sense_response_t);
+ transaction.cbw = &cbw;
+
+ res = _scsi_perform_transaction(lunp, &transaction, resp);
+ if (res == MSD_RESULT_OK) {
+ //transaction is OK; check length
+ if (transaction.data_processed < cbw.dCBWDataTransferLength) {
+ res = MSD_RESULT_TRANSPORT_ERROR;
+ }
}
+
return res;
}
static msd_result_t scsi_testunitready(USBHMassStorageLUNDriver *lunp) {
+ USBH_DEFINE_BUFFER(msd_cbw_t cbw);
msd_transaction_t transaction;
- msd_result_t res;
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = 0;
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
- transaction.cbw.bCBWCBLength = 6;
- transaction.cbw.CBWCB[0] = SCSI_CMD_TEST_UNIT_READY;
+ memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
+ cbw.dCBWDataTransferLength = 0;
+ cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
+ cbw.bCBWCBLength = 6;
+ cbw.CBWCB[0] = SCSI_CMD_TEST_UNIT_READY;
+ transaction.cbw = &cbw;
- res.tres = _msd_transaction(&transaction, lunp, NULL);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
- }
- return res;
+ return _scsi_perform_transaction(lunp, &transaction, NULL);
}
static msd_result_t scsi_readcapacity10(USBHMassStorageLUNDriver *lunp, scsi_readcapacity10_response_t *resp) {
+ USBH_DEFINE_BUFFER(msd_cbw_t cbw);
msd_transaction_t transaction;
msd_result_t res;
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = sizeof(scsi_readcapacity10_response_t);
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
- transaction.cbw.bCBWCBLength = 12;
- transaction.cbw.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10;
-
- res.tres = _msd_transaction(&transaction, lunp, resp);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
+ memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
+ cbw.dCBWDataTransferLength = sizeof(scsi_readcapacity10_response_t);
+ cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
+ cbw.bCBWCBLength = 12;
+ cbw.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10;
+ transaction.cbw = &cbw;
+
+ res = _scsi_perform_transaction(lunp, &transaction, resp);
+ if (res == MSD_RESULT_OK) {
+ //transaction is OK; check length
+ if (transaction.data_processed < cbw.dCBWDataTransferLength) {
+ res = MSD_RESULT_TRANSPORT_ERROR;
+ }
}
+
return res;
}
-static msd_result_t scsi_read10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, uint8_t *data) {
+static msd_result_t scsi_read10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, uint8_t *data, uint32_t *actual_len) {
+ USBH_DEFINE_BUFFER(msd_cbw_t cbw);
msd_transaction_t transaction;
msd_result_t res;
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
- transaction.cbw.bCBWCBLength = 10;
- transaction.cbw.CBWCB[0] = SCSI_CMD_READ_10;
- transaction.cbw.CBWCB[2] = (uint8_t)(lba >> 24);
- transaction.cbw.CBWCB[3] = (uint8_t)(lba >> 16);
- transaction.cbw.CBWCB[4] = (uint8_t)(lba >> 8);
- transaction.cbw.CBWCB[5] = (uint8_t)(lba);
- transaction.cbw.CBWCB[7] = (uint8_t)(n >> 8);
- transaction.cbw.CBWCB[8] = (uint8_t)(n);
-
- res.tres = _msd_transaction(&transaction, lunp, data);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
+ memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
+ cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
+ cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
+ cbw.bCBWCBLength = 10;
+ cbw.CBWCB[0] = SCSI_CMD_READ_10;
+ cbw.CBWCB[2] = (uint8_t)(lba >> 24);
+ cbw.CBWCB[3] = (uint8_t)(lba >> 16);
+ cbw.CBWCB[4] = (uint8_t)(lba >> 8);
+ cbw.CBWCB[5] = (uint8_t)(lba);
+ cbw.CBWCB[7] = (uint8_t)(n >> 8);
+ cbw.CBWCB[8] = (uint8_t)(n);
+ transaction.cbw = &cbw;
+
+ res = _scsi_perform_transaction(lunp, &transaction, data);
+ if (actual_len) {
+ *actual_len = transaction.data_processed;
}
+ if (res == MSD_RESULT_OK) {
+ //transaction is OK; check length
+ if (transaction.data_processed < cbw.dCBWDataTransferLength) {
+ res = MSD_RESULT_TRANSPORT_ERROR;
+ }
+ }
+
return res;
}
-static msd_result_t scsi_write10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, const uint8_t *data) {
+static msd_result_t scsi_write10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, const uint8_t *data, uint32_t *actual_len) {
+ USBH_DEFINE_BUFFER(msd_cbw_t cbw);
msd_transaction_t transaction;
msd_result_t res;
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_H2D;
- transaction.cbw.bCBWCBLength = 10;
- transaction.cbw.CBWCB[0] = SCSI_CMD_WRITE_10;
- transaction.cbw.CBWCB[2] = (uint8_t)(lba >> 24);
- transaction.cbw.CBWCB[3] = (uint8_t)(lba >> 16);
- transaction.cbw.CBWCB[4] = (uint8_t)(lba >> 8);
- transaction.cbw.CBWCB[5] = (uint8_t)(lba);
- transaction.cbw.CBWCB[7] = (uint8_t)(n >> 8);
- transaction.cbw.CBWCB[8] = (uint8_t)(n);
-
- res.tres = _msd_transaction(&transaction, lunp, (uint8_t *)data);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
+ memset(cbw.CBWCB, 0, sizeof(cbw.CBWCB));
+ cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
+ cbw.bmCBWFlags = MSD_CBWFLAGS_H2D;
+ cbw.bCBWCBLength = 10;
+ cbw.CBWCB[0] = SCSI_CMD_WRITE_10;
+ cbw.CBWCB[2] = (uint8_t)(lba >> 24);
+ cbw.CBWCB[3] = (uint8_t)(lba >> 16);
+ cbw.CBWCB[4] = (uint8_t)(lba >> 8);
+ cbw.CBWCB[5] = (uint8_t)(lba);
+ cbw.CBWCB[7] = (uint8_t)(n >> 8);
+ cbw.CBWCB[8] = (uint8_t)(n);
+ transaction.cbw = &cbw;
+
+ res = _scsi_perform_transaction(lunp, &transaction, (void *)data);
+ if (actual_len) {
+ *actual_len = transaction.data_processed;
}
+ if (res == MSD_RESULT_OK) {
+ //transaction is OK; check length
+ if (transaction.data_processed < cbw.dCBWDataTransferLength) {
+ res = MSD_RESULT_TRANSPORT_ERROR;
+ }
+ }
+
return res;
}
@@ -600,34 +704,6 @@ static const struct USBHMassStorageDriverVMT blk_vmt = {
(bool (*)(void *, BlockDeviceInfo *))usbhmsdLUNGetInfo
};
-
-
-static uint32_t _requestsense(USBHMassStorageLUNDriver *lunp) {
- scsi_sense_response_t sense;
- msd_result_t res;
-
- res = scsi_requestsense(lunp, &sense);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tREQUEST SENSE: Transaction error");
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- uerr("\tREQUEST SENSE: Command Failed");
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tREQUEST SENSE: Command Phase Error");
- goto failed;
- }
-
- uerrf("\tREQUEST SENSE: Sense key=%x, ASC=%02x, ASCQ=%02x",
- sense.byte[2] & 0xf, sense.byte[12], sense.byte[13]);
-
- return (sense.byte[2] & 0xf) | (sense.byte[12] << 8) | (sense.byte[13] << 16);
-
-failed:
- return 0xffffffff;
-}
-
void usbhmsdLUNObjectInit(USBHMassStorageLUNDriver *lunp) {
osalDbgCheck(lunp != NULL);
memset(lunp, 0, sizeof(*lunp));
@@ -680,71 +756,66 @@ bool usbhmsdLUNConnect(USBHMassStorageLUNDriver *lunp) {
osalMutexLock(&msdp->mtx);
- USBH_DEFINE_BUFFER(union {
- scsi_inquiry_response_t inq;
- scsi_readcapacity10_response_t cap; }, u);
-
- uinfo("INQUIRY...");
- res = scsi_inquiry(lunp, &u.inq);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tINQUIRY: Transaction error");
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- uerr("\tINQUIRY: Command Failed");
- _requestsense(lunp);
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tINQUIRY: Command Phase Error");
- goto failed;
- }
+ {
+ USBH_DEFINE_BUFFER(scsi_inquiry_response_t inq);
+ uinfo("INQUIRY...");
+ res = scsi_inquiry(lunp, &inq);
+ if (res == MSD_RESULT_DISCONNECTED) {
+ goto failed;
+ } else if (res == MSD_RESULT_TRANSPORT_ERROR) {
+ //retry?
+ goto failed;
+ } else if (res == MSD_RESULT_FAILED) {
+ //retry?
+ goto failed;
+ }
- uinfof("\tPDT=%02x", u.inq.peripheral & 0x1f);
- if (u.inq.peripheral != 0) {
- uerr("\tUnsupported PDT");
- goto failed;
+ uinfof("\tPDT=%02x", inq.peripheral & 0x1f);
+ if (inq.peripheral != 0) {
+ uerr("\tUnsupported PDT");
+ goto failed;
+ }
}
// Test if unit ready
- uint8_t i;
+ uint8_t i;
for (i = 0; i < 10; i++) {
uinfo("TEST UNIT READY...");
res = scsi_testunitready(lunp);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tTEST UNIT READY: Transaction error");
+ if (res == MSD_RESULT_DISCONNECTED) {
goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- uerr("\tTEST UNIT READY: Command Failed");
- _requestsense(lunp);
- continue;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tTEST UNIT READY: Command Phase Error");
+ } else if (res == MSD_RESULT_TRANSPORT_ERROR) {
+ //retry?
goto failed;
+ } else if (res == MSD_RESULT_FAILED) {
+ uinfo("\tTEST UNIT READY: Command Failed, retry");
+ osalThreadSleepMilliseconds(200);
+ continue;
}
uinfo("\tReady.");
break;
- // osalThreadSleepMilliseconds(200); // will raise 'code is unreachable' warning
}
if (i == 10) goto failed;
- // Read capacity
- uinfo("READ CAPACITY(10)...");
- res = scsi_readcapacity10(lunp, &u.cap);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tREAD CAPACITY(10): Transaction error");
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- uerr("\tREAD CAPACITY(10): Command Failed");
- _requestsense(lunp);
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tREAD CAPACITY(10): Command Phase Error");
- goto failed;
- }
- lunp->info.blk_size = __REV(u.cap.block_size);
- lunp->info.blk_num = __REV(u.cap.last_block_addr) + 1;
+ {
+ USBH_DEFINE_BUFFER(scsi_readcapacity10_response_t cap);
+ // Read capacity
+ uinfo("READ CAPACITY(10)...");
+ res = scsi_readcapacity10(lunp, &cap);
+ if (res == MSD_RESULT_DISCONNECTED) {
+ goto failed;
+ } else if (res == MSD_RESULT_TRANSPORT_ERROR) {
+ //retry?
+ goto failed;
+ } else if (res == MSD_RESULT_FAILED) {
+ //retry?
+ goto failed;
+ }
+
+ lunp->info.blk_size = __REV(cap.block_size);
+ lunp->info.blk_num = __REV(cap.last_block_addr) + 1;
+ }
+
uinfof("\tBlock size=%dbytes, blocks=%u (~%u MB)", lunp->info.blk_size, lunp->info.blk_num,
(uint32_t)(((uint64_t)lunp->info.blk_size * lunp->info.blk_num) / (1024UL * 1024UL)));
@@ -794,6 +865,7 @@ bool usbhmsdLUNRead(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
bool ret = HAL_FAILED;
uint16_t blocks;
msd_result_t res;
+ uint32_t actual_len;
osalSysLock();
if (lunp->state != BLK_READY) {
@@ -810,18 +882,14 @@ bool usbhmsdLUNRead(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
} else {
blocks = (uint16_t)n;
}
- res = scsi_read10(lunp, startblk, blocks, buffer);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tREAD (10): Transaction error");
+ res = scsi_read10(lunp, startblk, blocks, buffer, &actual_len);
+ if (res == MSD_RESULT_DISCONNECTED) {
goto exit;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- //TODO: request sense, and act appropriately
- uerr("\tREAD (10): Command Failed");
- _requestsense(lunp);
+ } else if (res == MSD_RESULT_TRANSPORT_ERROR) {
+ //retry?
goto exit;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tREAD (10): Command Phase Error");
+ } else if (res == MSD_RESULT_FAILED) {
+ //retry?
goto exit;
}
n -= blocks;
@@ -851,6 +919,7 @@ bool usbhmsdLUNWrite(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
bool ret = HAL_FAILED;
uint16_t blocks;
msd_result_t res;
+ uint32_t actual_len;
osalSysLock();
if (lunp->state != BLK_READY) {
@@ -867,18 +936,14 @@ bool usbhmsdLUNWrite(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
} else {
blocks = (uint16_t)n;
}
- res = scsi_write10(lunp, startblk, blocks, buffer);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tWRITE (10): Transaction error");
+ res = scsi_write10(lunp, startblk, blocks, buffer, &actual_len);
+ if (res == MSD_RESULT_DISCONNECTED) {
goto exit;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- //TODO: request sense, and act appropriately
- uerr("\tWRITE (10): Command Failed");
- _requestsense(lunp);
+ } else if (res == MSD_RESULT_TRANSPORT_ERROR) {
+ //retry?
goto exit;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tWRITE (10): Command Phase Error");
+ } else if (res == MSD_RESULT_FAILED) {
+ //retry?
goto exit;
}
n -= blocks;
@@ -936,4 +1001,13 @@ void usbhmsdObjectInit(USBHMassStorageDriver *msdp) {
osalMutexObjectInit(&msdp->mtx);
}
+void usbhmsdInit(void) {
+ uint8_t i;
+ for (i = 0; i < HAL_USBHMSD_MAX_INSTANCES; i++) {
+ usbhmsdObjectInit(&USBHMSD[i]);
+ }
+ for (i = 0; i < HAL_USBHMSD_MAX_LUNS; i++) {
+ usbhmsdLUNObjectInit(&MSBLKD[i]);
+ }
+}
#endif
diff --git a/os/hal/src/usbh/hal_usbh_uvc.c b/os/hal/src/usbh/hal_usbh_uvc.c
index 09a0f1d..9cbbb03 100644
--- a/os/hal/src/usbh/hal_usbh_uvc.c
+++ b/os/hal/src/usbh/hal_usbh_uvc.c
@@ -1,6 +1,6 @@
/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
+ ChibiOS - Copyright (C) 2006..2017 Giovanni Di Sirio
+ Copyright (C) 2015..2017 Diego Ismirlian, (dismirlian (at) google's mail)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,10 +13,9 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-*/
+ */
#include "hal.h"
-#include "hal_usbh.h"
#if HAL_USBH_USE_UVC
@@ -28,6 +27,10 @@
#error "USBHUVC needs HAL_USBH_USE_IAD"
#endif
+#include "usbh/dev/uvc.h"
+#include "usbh/internal.h"
+#include <string.h>
+
#if USBHUVC_DEBUG_ENABLE_TRACE
#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
@@ -61,6 +64,9 @@
#endif
+USBHUVCDriver USBHUVCD[HAL_USBHUVC_MAX_INSTANCES];
+
+
static usbh_baseclassdriver_t *uvc_load(usbh_device_t *dev,
const uint8_t *descriptor, uint16_t rem);
static void uvc_unload(usbh_baseclassdriver_t *drv);
@@ -73,16 +79,653 @@ const usbh_classdriverinfo_t usbhuvcClassDriverInfo = {
0x0e, 0x03, 0x00, "UVC", &class_driver_vmt
};
+static bool _request(USBHUVCDriver *uvcdp,
+ uint8_t bRequest, uint8_t entity, uint8_t control,
+ uint16_t wLength, uint8_t *data, uint8_t interf) {
+
+ usbh_urbstatus_t res;
+
+ if (bRequest & 0x80) {
+ res = usbhControlRequest(uvcdp->dev,
+ USBH_REQTYPE_CLASSIN(USBH_REQTYPE_RECIP_INTERFACE),
+ bRequest,
+ ((control) << 8),
+ (interf) | ((entity) << 8),
+ wLength, data);
+ } else {
+ res = usbhControlRequest(uvcdp->dev,
+ USBH_REQTYPE_CLASSOUT(USBH_REQTYPE_RECIP_INTERFACE),
+ bRequest,
+ ((control) << 8),
+ (interf) | ((entity) << 8),
+ wLength, data);
+ }
+
+ if (res != USBH_URBSTATUS_OK)
+ return HAL_FAILED;
+
+ return HAL_SUCCESS;
+}
+
+bool usbhuvcVCRequest(USBHUVCDriver *uvcdp,
+ uint8_t bRequest, uint8_t entity, uint8_t control,
+ uint16_t wLength, uint8_t *data) {
+ return _request(uvcdp, bRequest, entity, control, wLength, data, if_get(&uvcdp->ivc)->bInterfaceNumber);
+}
+
+bool usbhuvcVSRequest(USBHUVCDriver *uvcdp,
+ uint8_t bRequest, uint8_t control,
+ uint16_t wLength, uint8_t *data) {
+
+ return _request(uvcdp, bRequest, 0, control, wLength, data, if_get(&uvcdp->ivs)->bInterfaceNumber);
+}
+
+static bool _set_vs_alternate(USBHUVCDriver *uvcdp, uint16_t min_ep_size) {
+
+ if (min_ep_size == 0) {
+ uinfo("Selecting Alternate setting 0");
+ return usbhStdReqSetInterface(uvcdp->dev, if_get(&uvcdp->ivs)->bInterfaceNumber, 0);
+ }
+
+ if_iterator_t iif = uvcdp->ivs;
+ generic_iterator_t iep;
+ const usbh_endpoint_descriptor_t *ep = NULL;
+ uint8_t alt = 0;
+ uint16_t sz = 0xffff;
+
+ uinfof("Searching alternate setting with min_ep_size=%d", min_ep_size);
+
+ for (; iif.valid; if_iter_next(&iif)) {
+ const usbh_interface_descriptor_t *const ifdesc = if_get(&iif);
+
+ if ((ifdesc->bInterfaceClass != UVC_CC_VIDEO)
+ || (ifdesc->bInterfaceSubClass != UVC_SC_VIDEOSTREAMING))
+ continue;
+
+ uinfof("\tScanning alternate setting=%d", ifdesc->bAlternateSetting);
+
+ if (ifdesc->bNumEndpoints == 0)
+ continue;
+
+ for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) {
+ const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
+ if (((epdesc->bmAttributes & 0x03) == USBH_EPTYPE_ISO)
+ && ((epdesc->bEndpointAddress & 0x80) == USBH_EPDIR_IN)) {
+
+ uinfof("\t Endpoint wMaxPacketSize = %d", epdesc->wMaxPacketSize);
+
+ if (epdesc->wMaxPacketSize >= min_ep_size) {
+ if (epdesc->wMaxPacketSize < sz) {
+ uinfo("\t Found new optimal alternate setting");
+ sz = epdesc->wMaxPacketSize;
+ alt = ifdesc->bAlternateSetting;
+ ep = epdesc;
+ }
+ }
+ }
+ }
+ }
+
+ if (ep && alt) {
+ uinfof("\tSelecting Alternate setting %d", alt);
+ if (usbhStdReqSetInterface(uvcdp->dev, if_get(&uvcdp->ivs)->bInterfaceNumber, alt) == HAL_SUCCESS) {
+ usbhEPObjectInit(&uvcdp->ep_iso, uvcdp->dev, ep);
+ usbhEPSetName(&uvcdp->ep_iso, "UVC[ISO ]");
+ return HAL_SUCCESS;
+ }
+ }
+
+ return HAL_FAILED;
+}
+
+#if USBH_DEBUG_ENABLE && USBHUVC_DEBUG_ENABLE_INFO
+void usbhuvcPrintProbeCommit(const usbh_uvc_ctrl_vs_probecommit_data_t *pc) {
+
+ //uinfof("UVC: probe/commit data:");
+ uinfof("\tbmHint=%04x", pc->bmHint);
+ uinfof("\tbFormatIndex=%d, bFrameIndex=%d, dwFrameInterval=%u",
+ pc->bFormatIndex, pc->bFrameIndex, pc->dwFrameInterval);
+ uinfof("\twKeyFrameRate=%d, wPFrameRate=%d, wCompQuality=%u, wCompWindowSize=%u",
+ pc->wKeyFrameRate, pc->wPFrameRate, pc->wCompQuality, pc->wCompWindowSize);
+ uinfof("\twDelay=%d", pc->wDelay);
+ uinfof("\tdwMaxVideoFrameSize=%u", pc->dwMaxVideoFrameSize);
+ uinfof("\tdwMaxPayloadTransferSize=%u", pc->dwMaxPayloadTransferSize);
+/* uinfof("\tdwClockFrequency=%u", pc->dwClockFrequency);
+ uinfof("\tbmFramingInfo=%02x", pc->bmFramingInfo);
+ uinfof("\tbPreferedVersion=%d, bMinVersion=%d, bMaxVersion=%d",
+ pc->bPreferedVersion, pc->bMinVersion, pc->bMaxVersion); */
+}
+#endif
+
+static void _post(USBHUVCDriver *uvcdp, usbh_urb_t *urb, memory_pool_t *mp, uint16_t type) {
+ usbhuvc_message_base_t *const msg = (usbhuvc_message_base_t *)urb->buff - 1;
+ msg->timestamp = osalOsGetSystemTimeX();
+
+ usbhuvc_message_base_t *const new_msg = (usbhuvc_message_base_t *)chPoolAllocI(mp);
+ if (new_msg != NULL) {
+ /* allocated the new buffer, now try to post the message to the mailbox */
+ if (chMBPostI(&uvcdp->mb, (msg_t)msg) == MSG_OK) {
+ /* everything OK, complete the missing fields */
+ msg->type = type;
+ msg->length = urb->actualLength;
+
+ /* change the URB's buffer to the newly allocated one */
+ urb->buff = (uint8_t *)(new_msg + 1);
+ } else {
+ /* couldn't post the message, free the newly allocated buffer */
+ uerr("UVC: error, mailbox overrun");
+ chPoolFreeI(&uvcdp->mp_status, new_msg);
+ }
+ } else {
+ uerrf("UVC: error, %s pool overrun", mp == &uvcdp->mp_data ? "data" : "status");
+ }
+}
+
+static void _cb_int(usbh_urb_t *urb) {
+ USBHUVCDriver *uvcdp = (USBHUVCDriver *)urb->userData;
+
+ switch (urb->status) {
+ case USBH_URBSTATUS_OK:
+ if (urb->actualLength >= 2) {
+ _post(uvcdp, urb, &uvcdp->mp_status, USBHUVC_MESSAGETYPE_STATUS);
+ } else {
+ uerrf("UVC: INT IN, actualLength=%d", urb->actualLength);
+ }
+ break;
+ case USBH_URBSTATUS_TIMEOUT: /* the device NAKed */
+ udbg("UVC: INT IN no info");
+ break;
+ case USBH_URBSTATUS_DISCONNECTED:
+ case USBH_URBSTATUS_CANCELLED:
+ uwarn("UVC: INT IN status = DISCONNECTED/CANCELLED, aborting");
+ return;
+ default:
+ uerrf("UVC: INT IN error, unexpected status = %d", urb->status);
+ break;
+ }
+
+ usbhURBObjectResetI(urb);
+ usbhURBSubmitI(urb);
+}
+
+static void _cb_iso(usbh_urb_t *urb) {
+ USBHUVCDriver *uvcdp = (USBHUVCDriver *)urb->userData;
+
+ if ((urb->status == USBH_URBSTATUS_DISCONNECTED)
+ || (urb->status == USBH_URBSTATUS_CANCELLED)) {
+ uwarn("UVC: ISO IN status = DISCONNECTED/CANCELLED, aborting");
+ return;
+ }
+
+ if (urb->status != USBH_URBSTATUS_OK) {
+ uerrf("UVC: ISO IN error, unexpected status = %d", urb->status);
+ } else if (urb->actualLength >= 2) {
+ const uint8_t *const buff = (const uint8_t *)urb->buff;
+ if (buff[0] < 2) {
+ uerrf("UVC: ISO IN, bHeaderLength=%d", buff[0]);
+ } else if (buff[0] > urb->actualLength) {
+ uerrf("UVC: ISO IN, bHeaderLength=%d > actualLength=%d", buff[0], urb->actualLength);
+ } else {
+ udbgf("UVC: ISO IN len=%d, hdr=%d, FID=%d, EOF=%d, ERR=%d, EOH=%d",
+ urb->actualLength,
+ buff[0],
+ buff[1] & UVC_HDR_FID,
+ buff[1] & UVC_HDR_EOF,
+ buff[1] & UVC_HDR_ERR,
+ buff[1] & UVC_HDR_EOH);
+
+ if ((urb->actualLength > buff[0])
+ || (buff[1] & (UVC_HDR_EOF | UVC_HDR_ERR))) {
+ _post(uvcdp, urb, &uvcdp->mp_data, USBHUVC_MESSAGETYPE_DATA);
+ } else {
+ udbgf("UVC: ISO IN skip: len=%d, hdr=%d, FID=%d, EOF=%d, ERR=%d, EOH=%d",
+ urb->actualLength,
+ buff[0],
+ buff[1] & UVC_HDR_FID,
+ buff[1] & UVC_HDR_EOF,
+ buff[1] & UVC_HDR_ERR,
+ buff[1] & UVC_HDR_EOH);
+ }
+ }
+ } else if (urb->actualLength > 0) {
+ uerrf("UVC: ISO IN, actualLength=%d", urb->actualLength);
+ }
+
+ usbhURBObjectResetI(urb);
+ usbhURBSubmitI(urb);
+}
+
+
+bool usbhuvcStreamStart(USBHUVCDriver *uvcdp, uint16_t min_ep_sz) {
+ bool ret = HAL_FAILED;
+ osalSysLock();
+ osalDbgCheck(uvcdp && (uvcdp->state != USBHUVC_STATE_UNINITIALIZED) &&
+ (uvcdp->state != USBHUVC_STATE_BUSY));
+ if (uvcdp->state == USBHUVC_STATE_STREAMING) {
+ osalSysUnlock();
+ return HAL_SUCCESS;
+ }
+ if (uvcdp->state != USBHUVC_STATE_READY) {
+ osalSysUnlock();
+ return HAL_FAILED;
+ }
+ uvcdp->state = USBHUVC_STATE_BUSY;
+ osalSysUnlock();
+
+ //set the alternate setting
+ if (_set_vs_alternate(uvcdp, min_ep_sz) != HAL_SUCCESS)
+ goto exit;
+
+ //reserve working RAM
+ uint32_t datapackets;
+ uint32_t data_sz = (uvcdp->ep_iso.wMaxPacketSize + sizeof(usbhuvc_message_data_t) + 3) & ~3;
+
+ datapackets = HAL_USBHUVC_WORK_RAM_SIZE / data_sz;
+ if (datapackets == 0) {
+ uerr("Not enough work RAM");
+ goto failed;
+ }
+
+ uint32_t workramsz = datapackets * data_sz;
+ uinfof("Reserving %u bytes of RAM (%d data packets of %d bytes)", workramsz, datapackets, data_sz);
+ if (datapackets > (HAL_USBHUVC_MAX_MAILBOX_SZ - HAL_USBHUVC_STATUS_PACKETS_COUNT)) {
+ uwarn("Mailbox may overflow, use a larger HAL_USBHUVC_MAX_MAILBOX_SZ. UVC will under-utilize the assigned work RAM.");
+ }
+ chMBResumeX(&uvcdp->mb);
+
+ uvcdp->mp_data_buffer = chHeapAlloc(NULL, workramsz);
+ if (uvcdp->mp_data_buffer == NULL) {
+ uerr("Couldn't reserve RAM");
+ goto failed;
+ }
+
+ //initialize the mempool
+ const uint8_t *elem = (const uint8_t *)uvcdp->mp_data_buffer;
+ chPoolObjectInit(&uvcdp->mp_data, data_sz, NULL);
+ while (datapackets--) {
+ chPoolFree(&uvcdp->mp_data, (void *)elem);
+ elem += data_sz;
+ }
+
+ //open the endpoint
+ usbhEPOpen(&uvcdp->ep_iso);
+
+ //allocate 1 buffer and submit the first transfer
+ usbhuvc_message_data_t *const msg = (usbhuvc_message_data_t *)chPoolAlloc(&uvcdp->mp_data);
+ osalDbgCheck(msg);
+ usbhURBObjectInit(&uvcdp->urb_iso, &uvcdp->ep_iso, _cb_iso, uvcdp, msg->data, uvcdp->ep_iso.wMaxPacketSize);
+ osalSysLock();
+ usbhURBSubmitI(&uvcdp->urb_iso);
+ osalOsRescheduleS();
+ osalSysUnlock();
+
+ ret = HAL_SUCCESS;
+ goto exit;
+
+failed:
+ _set_vs_alternate(uvcdp, 0);
+ if (uvcdp->mp_data_buffer)
+ chHeapFree(uvcdp->mp_data_buffer);
+
+exit:
+ osalSysLock();
+ if (ret == HAL_SUCCESS)
+ uvcdp->state = USBHUVC_STATE_STREAMING;
+ else
+ uvcdp->state = USBHUVC_STATE_READY;
+ osalSysUnlock();
+ return ret;
+}
+
+bool usbhuvcStreamStop(USBHUVCDriver *uvcdp) {
+ osalSysLock();
+ osalDbgCheck(uvcdp && (uvcdp->state != USBHUVC_STATE_UNINITIALIZED) &&
+ (uvcdp->state != USBHUVC_STATE_BUSY));
+ if (uvcdp->state != USBHUVC_STATE_STREAMING) {
+ osalSysUnlock();
+ return HAL_SUCCESS;
+ }
+ uvcdp->state = USBHUVC_STATE_BUSY;
+
+ //close the ISO endpoint
+ usbhEPCloseS(&uvcdp->ep_iso);
+
+ //purge the mailbox
+ chMBResetI(&uvcdp->mb); //TODO: the status messages are lost!!
+ chMtxLockS(&uvcdp->mtx);
+ osalSysUnlock();
+
+ //free the working memory
+ chHeapFree(uvcdp->mp_data_buffer);
+ uvcdp->mp_data_buffer = 0;
+
+ //set alternate setting to 0
+ _set_vs_alternate(uvcdp, 0);
+
+ osalSysLock();
+ uvcdp->state = USBHUVC_STATE_READY;
+ chMtxUnlockS(&uvcdp->mtx);
+ osalSysUnlock();
+ return HAL_SUCCESS;
+}
+
+bool usbhuvcFindVSDescriptor(USBHUVCDriver *uvcdp,
+ generic_iterator_t *ics,
+ uint8_t bDescriptorSubtype,
+ bool start) {
+
+ if (start)
+ cs_iter_init(ics, (generic_iterator_t *)&uvcdp->ivs);
+ else
+ cs_iter_next(ics);
+
+ for (; ics->valid; cs_iter_next(ics)) {
+ if (ics->curr[1] != UVC_CS_INTERFACE)
+ break;
+ if (ics->curr[2] == bDescriptorSubtype)
+ return HAL_SUCCESS;
+ if (!start)
+ break;
+ }
+ return HAL_FAILED;
+}
+
+void usbhuvcResetPC(USBHUVCDriver *uvcdp) {
+ memset(&uvcdp->pc, 0, sizeof(uvcdp->pc));
+}
+
+bool usbhuvcProbe(USBHUVCDriver *uvcdp) {
+// memset(&uvcdp->pc_min, 0, sizeof(uvcdp->pc_min));
+// memset(&uvcdp->pc_max, 0, sizeof(uvcdp->pc_max));
+
+ if (usbhuvcVSRequest(uvcdp, UVC_SET_CUR, UVC_CTRL_VS_PROBE_CONTROL, sizeof(uvcdp->pc), (uint8_t *)&uvcdp->pc) != HAL_SUCCESS)
+ return HAL_FAILED;
+ if (usbhuvcVSRequest(uvcdp, UVC_GET_CUR, UVC_CTRL_VS_PROBE_CONTROL, sizeof(uvcdp->pc), (uint8_t *)&uvcdp->pc) != HAL_SUCCESS)
+ return HAL_FAILED;
+ if (usbhuvcVSRequest(uvcdp, UVC_GET_MAX, UVC_CTRL_VS_PROBE_CONTROL, sizeof(uvcdp->pc_max), (uint8_t *)&uvcdp->pc_max) != HAL_SUCCESS)
+ return HAL_FAILED;
+ if (usbhuvcVSRequest(uvcdp, UVC_GET_MIN, UVC_CTRL_VS_PROBE_CONTROL, sizeof(uvcdp->pc_min), (uint8_t *)&uvcdp->pc_min) != HAL_SUCCESS)
+ return HAL_FAILED;
+ return HAL_SUCCESS;
+}
+
+bool usbhuvcCommit(USBHUVCDriver *uvcdp) {
+ if (usbhuvcVSRequest(uvcdp, UVC_SET_CUR, UVC_CTRL_VS_COMMIT_CONTROL, sizeof(uvcdp->pc), (uint8_t *)&uvcdp->pc) != HAL_SUCCESS)
+ return HAL_FAILED;
+
+ osalSysLock();
+ if (uvcdp->state == USBHUVC_STATE_ACTIVE)
+ uvcdp->state = USBHUVC_STATE_READY;
+ osalSysUnlock();
+ return HAL_SUCCESS;
+}
+
+uint32_t usbhuvcEstimateRequiredEPSize(USBHUVCDriver *uvcdp, const uint8_t *formatdesc,
+ const uint8_t *framedesc, uint32_t dwFrameInterval) {
+
+ osalDbgCheck(framedesc);
+ osalDbgCheck(framedesc[0] > 3);
+ osalDbgCheck(framedesc[1] == UVC_CS_INTERFACE);
+ osalDbgCheck(formatdesc);
+ osalDbgCheck(formatdesc[0] > 3);
+ osalDbgCheck(formatdesc[1] == UVC_CS_INTERFACE);
+
+ uint16_t w, h, div, mul;
+ uint8_t bpp;
+
+ switch (framedesc[2]) {
+ case UVC_VS_FRAME_MJPEG: {
+ const usbh_uvc_frame_mjpeg_t *frame = (const usbh_uvc_frame_mjpeg_t *)framedesc;
+ //const usbh_uvc_format_mjpeg_t *fmt = (const usbh_uvc_format_mjpeg_t *)formatdesc;
+ w = frame->wWidth;
+ h = frame->wHeight;
+ bpp = 16; //TODO: check this!!
+ mul = 1;
+ div = 5; //TODO: check this estimate
+ } break;
+ case UVC_VS_FRAME_UNCOMPRESSED: {
+ const usbh_uvc_frame_uncompressed_t *frame = (const usbh_uvc_frame_uncompressed_t *)framedesc;
+ const usbh_uvc_format_uncompressed *fmt = (const usbh_uvc_format_uncompressed *)formatdesc;
+ w = frame->wWidth;
+ h = frame->wHeight;
+ bpp = fmt->bBitsPerPixel;
+ mul = div = 1;
+ } break;
+ default:
+ uwarn("Unsupported format");
+ return 0xffffffff;
+ }
+
+ uint32_t sz = w * h / 8 * bpp;
+ sz *= 10000000UL / dwFrameInterval;
+ sz /= 1000;
+
+ if (uvcdp->dev->speed == USBH_DEVSPEED_HIGH)
+ div *= 8;
+
+ return (sz * mul) / div + 12;
+}
+
+void usbhuvcObjectInit(USBHUVCDriver *uvcdp) {
+ osalDbgCheck(uvcdp != NULL);
+ memset(uvcdp, 0, sizeof(*uvcdp));
+ uvcdp->info = &usbhuvcClassDriverInfo;
+ chMBObjectInit(&uvcdp->mb, uvcdp->mb_buff, HAL_USBHUVC_MAX_MAILBOX_SZ);
+ chMtxObjectInit(&uvcdp->mtx);
+ uvcdp->state = USBHUVC_STATE_STOP;
+}
+
static usbh_baseclassdriver_t *uvc_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
- (void)dev;
- (void)descriptor;
- (void)rem;
+
+ USBHUVCDriver *uvcdp;
+ uint8_t i;
+
+ if (descriptor[1] != USBH_DT_INTERFACE_ASSOCIATION)
+ return NULL;
+
+ /* alloc driver */
+ for (i = 0; i < HAL_USBHUVC_MAX_INSTANCES; i++) {
+ if (USBHUVCD[i].dev == NULL) {
+ uvcdp = &USBHUVCD[i];
+ goto alloc_ok;
+ }
+ }
+
+ uwarn("Can't alloc UVC driver");
+
+ /* can't alloc */
return NULL;
+
+alloc_ok:
+ /* initialize the driver's variables */
+ uvcdp->ivc.curr = uvcdp->ivs.curr = NULL;
+
+ usbhEPSetName(&dev->ctrl, "UVC[CTRL]");
+
+ const usbh_ia_descriptor_t *iad = (const usbh_ia_descriptor_t *)descriptor;
+ if_iterator_t iif;
+ generic_iterator_t ics;
+ generic_iterator_t iep;
+
+ iif.iad = iad;
+ iif.curr = descriptor;
+ iif.rem = rem;
+
+ for (if_iter_next(&iif); iif.valid; if_iter_next(&iif)) {
+ if (iif.iad != iad) break;
+
+ const usbh_interface_descriptor_t *const ifdesc = if_get(&iif);
+ if (ifdesc->bInterfaceClass != UVC_CC_VIDEO) {
+ uwarnf("Skipping Interface %d (class != UVC_CC_VIDEO)",
+ ifdesc->bInterfaceNumber);
+ continue;
+ }
+
+ uinfof("Interface %d, Alt=%d, Class=UVC_CC_VIDEO, Subclass=%02x",
+ ifdesc->bInterfaceNumber,
+ ifdesc->bAlternateSetting,
+ ifdesc->bInterfaceSubClass);
+
+ switch (ifdesc->bInterfaceSubClass) {
+ case UVC_SC_VIDEOCONTROL:
+ if (uvcdp->ivc.curr == NULL) {
+ uvcdp->ivc = iif;
+ }
+ for (cs_iter_init(&ics, (generic_iterator_t *)&iif); ics.valid; cs_iter_next(&ics)) {
+ if (ics.curr[1] != UVC_CS_INTERFACE) {
+ uwarnf("Unknown descriptor=%02X", ics.curr[1]);
+ continue;
+ }
+ switch (ics.curr[2]) {
+ case UVC_VC_HEADER:
+ uinfo(" VC_HEADER"); break;
+ case UVC_VC_INPUT_TERMINAL:
+ uinfof(" VC_INPUT_TERMINAL, ID=%d", ics.curr[3]); break;
+ case UVC_VC_OUTPUT_TERMINAL:
+ uinfof(" VC_OUTPUT_TERMINAL, ID=%d", ics.curr[3]); break;
+ case UVC_VC_SELECTOR_UNIT:
+ uinfof(" VC_SELECTOR_UNIT, ID=%d", ics.curr[3]); break;
+ case UVC_VC_PROCESSING_UNIT:
+ uinfof(" VC_PROCESSING_UNIT, ID=%d", ics.curr[3]); break;
+ case UVC_VC_EXTENSION_UNIT:
+ uinfof(" VC_EXTENSION_UNIT, ID=%d", ics.curr[3]); break;
+ default:
+ uwarnf("Unknown video bDescriptorSubtype=%02x", ics.curr[2]);
+ break;
+ }
+ }
+ break;
+ case UVC_SC_VIDEOSTREAMING:
+ if (uvcdp->ivs.curr == NULL) {
+ uvcdp->ivs = iif;
+ }
+ for (cs_iter_init(&ics, (generic_iterator_t *)&iif); ics.valid; cs_iter_next(&ics)) {
+ if (ics.curr[1] != UVC_CS_INTERFACE) {
+ uwarnf("Unknown descriptor=%02X", ics.curr[1]);
+ continue;
+ }
+ switch (ics.curr[2]) {
+ case UVC_VS_INPUT_HEADER:
+ uinfo(" VS_INPUT_HEADER"); break;
+ case UVC_VS_OUTPUT_HEADER:
+ uinfo(" VS_OUTPUT_HEADER"); break;
+ case UVC_VS_STILL_IMAGE_FRAME:
+ uinfo(" VS_STILL_IMAGE_FRAME"); break;
+
+ case UVC_VS_FORMAT_UNCOMPRESSED:
+ uinfof(" VS_FORMAT_UNCOMPRESSED, bFormatIndex=%d", ics.curr[3]); break;
+ case UVC_VS_FORMAT_MPEG2TS:
+ uinfof(" VS_FORMAT_MPEG2TS, bFormatIndex=%d", ics.curr[3]); break;
+ case UVC_VS_FORMAT_DV:
+ uinfof(" VS_FORMAT_DV, bFormatIndex=%d", ics.curr[3]); break;
+ case UVC_VS_FORMAT_MJPEG:
+ uinfof(" VS_FORMAT_MJPEG, bFormatIndex=%d", ics.curr[3]); break;
+ case UVC_VS_FORMAT_FRAME_BASED:
+ uinfof(" VS_FORMAT_FRAME_BASED, bFormatIndex=%d", ics.curr[3]); break;
+ case UVC_VS_FORMAT_STREAM_BASED:
+ uinfof(" VS_FORMAT_STREAM_BASED, bFormatIndex=%d", ics.curr[3]); break;
+
+ case UVC_VS_FRAME_UNCOMPRESSED:
+ uinfof(" VS_FRAME_UNCOMPRESSED, bFrameIndex=%d", ics.curr[3]); break;
+ case UVC_VS_FRAME_MJPEG:
+ uinfof(" VS_FRAME_MJPEG, bFrameIndex=%d", ics.curr[3]); break;
+ case UVC_VS_FRAME_FRAME_BASED:
+ uinfof(" VS_FRAME_FRAME_BASED, bFrameIndex=%d", ics.curr[3]); break;
+
+ case UVC_VS_COLOR_FORMAT:
+ uinfo(" VS_COLOR_FORMAT"); break;
+ default:
+ uwarnf("Unknown video bDescriptorSubtype=%02x", ics.curr[2]);
+ break;
+ }
+ }
+ break;
+ default:
+ uwarnf("Unknown video bInterfaceSubClass=%02x", ifdesc->bInterfaceSubClass);
+ break;
+ }
+
+ for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) {
+ const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
+
+ if ((ifdesc->bInterfaceSubClass == UVC_SC_VIDEOCONTROL)
+ && ((epdesc->bmAttributes & 0x03) == USBH_EPTYPE_INT)
+ && ((epdesc->bEndpointAddress & 0x80) == USBH_EPDIR_IN)) {
+ /* found VC interrupt endpoint */
+ uinfof(" VC Interrupt endpoint; %02x, bInterval=%d",
+ epdesc->bEndpointAddress, epdesc->bInterval);
+ usbhEPObjectInit(&uvcdp->ep_int, dev, epdesc);
+ usbhEPSetName(&uvcdp->ep_int, "UVC[INT ]");
+ } else if ((ifdesc->bInterfaceSubClass == UVC_SC_VIDEOSTREAMING)
+ && ((epdesc->bmAttributes & 0x03) == USBH_EPTYPE_ISO)
+ && ((epdesc->bEndpointAddress & 0x80) == USBH_EPDIR_IN)) {
+ /* found VS isochronous endpoint */
+ uinfof(" VS Isochronous endpoint; %02x, bInterval=%d, bmAttributes=%02x",
+ epdesc->bEndpointAddress, epdesc->bInterval, epdesc->bmAttributes);
+ } else {
+ /* unknown EP */
+ uwarnf(" <unknown endpoint>, bEndpointAddress=%02x, bmAttributes=%02x",
+ epdesc->bEndpointAddress, epdesc->bmAttributes);
+ }
+
+ for (cs_iter_init(&ics, &iep); ics.valid; cs_iter_next(&ics)) {
+ uinfof(" CS_ENDPOINT bLength=%d, bDescriptorType=%02X",
+ ics.curr[0], ics.curr[1]);
+ }
+ }
+ }
+
+ if ((uvcdp->ivc.curr == NULL) || (uvcdp->ivs.curr == NULL)) {
+ return NULL;
+ }
+
+// uvcdp->dev = dev;
+
+ _set_vs_alternate(uvcdp, 0);
+
+ /* initialize the INT endpoint */
+ chPoolObjectInit(&uvcdp->mp_status, sizeof(usbhuvc_message_status_t), NULL);
+ for(i = 0; i < HAL_USBHUVC_STATUS_PACKETS_COUNT; i++)
+ chPoolFree(&uvcdp->mp_status, &uvcdp->mp_status_buffer[i]);
+
+ usbhEPOpen(&uvcdp->ep_int);
+
+ usbhuvc_message_status_t *const msg = (usbhuvc_message_status_t *)chPoolAlloc(&uvcdp->mp_status);
+ osalDbgCheck(msg);
+ usbhURBObjectInit(&uvcdp->urb_int, &uvcdp->ep_int, _cb_int, uvcdp, msg->data, USBHUVC_MAX_STATUS_PACKET_SZ);
+ osalSysLock();
+ usbhURBSubmitI(&uvcdp->urb_int);
+ uvcdp->state = USBHUVC_STATE_ACTIVE;
+ osalOsRescheduleS();
+ osalSysUnlock();
+
+ dev->keepFullCfgDesc++;
+ return (usbh_baseclassdriver_t *)uvcdp;
}
static void uvc_unload(usbh_baseclassdriver_t *drv) {
- (void)drv;
+ USBHUVCDriver *const uvcdp = (USBHUVCDriver *)drv;
+
+ usbhuvcStreamStop(uvcdp);
+
+ usbhEPClose(&uvcdp->ep_int);
+
+ //TODO: free
+
+ if (drv->dev->keepFullCfgDesc)
+ drv->dev->keepFullCfgDesc--;
+
+ osalSysLock();
+ uvcdp->state = USBHUVC_STATE_STOP;
+ osalSysUnlock();
+}
+
+void usbhuvcInit(void) {
+ uint8_t i;
+ for (i = 0; i < HAL_USBHUVC_MAX_INSTANCES; i++) {
+ usbhuvcObjectInit(&USBHUVCD[i]);
+ }
}
#endif
diff --git a/os/various/fatfs_bindings/fatfs.mk b/os/various/fatfs_bindings/fatfs.mk
new file mode 100644
index 0000000..238037e
--- /dev/null
+++ b/os/various/fatfs_bindings/fatfs.mk
@@ -0,0 +1,7 @@
+# FATFS files.
+FATFSSRC = ${CHIBIOS_CONTRIB}/os/various/fatfs_bindings/fatfs_diskio.c \
+ ${CHIBIOS}/os/various/fatfs_bindings/fatfs_syscall.c \
+ ${CHIBIOS}/ext/fatfs/src/ff.c \
+ ${CHIBIOS}/ext/fatfs/src/option/unicode.c
+
+FATFSINC = ${CHIBIOS}/ext/fatfs/src
diff --git a/os/various/fatfs_bindings/fatfs_diskio.c b/os/various/fatfs_bindings/fatfs_diskio.c
new file mode 100644
index 0000000..6949310
--- /dev/null
+++ b/os/various/fatfs_bindings/fatfs_diskio.c
@@ -0,0 +1,320 @@
+/*-----------------------------------------------------------------------*/
+/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
+/*-----------------------------------------------------------------------*/
+/* This is a stub disk I/O module that acts as front end of the existing */
+/* disk I/O modules and attach it to FatFs module with common interface. */
+/*-----------------------------------------------------------------------*/
+
+#include "hal.h"
+#include "ffconf.h"
+#include "diskio.h"
+#include "usbh/dev/msd.h"
+
+#if HAL_USE_MMC_SPI && HAL_USE_SDC
+#error "cannot specify both MMC_SPI and SDC drivers"
+#endif
+
+#if HAL_USE_MMC_SPI
+extern MMCDriver MMCD1;
+#elif HAL_USE_SDC
+extern SDCDriver SDCD1;
+#elif HAL_USBH_USE_MSD
+
+#else
+#error "MMC_SPI, SDC or USBH_MSD driver must be specified"
+#endif
+
+/*-----------------------------------------------------------------------*/
+/* Correspondence between physical drive number and physical drive. */
+#if HAL_USE_MMC_SPI
+#define MMC 0
+#endif
+
+#if HAL_USE_SDC
+#define SDC 0
+#endif
+
+#if HAL_USBH_USE_MSD
+#if defined(MMC) || defined(SDC)
+#define MSDLUN0 1
+#else
+#define MSDLUN0 0
+#endif
+#endif
+
+/*-----------------------------------------------------------------------*/
+/* Inidialize a Drive */
+
+DSTATUS disk_initialize (
+ BYTE pdrv /* Physical drive nmuber (0..) */
+)
+{
+ DSTATUS stat;
+
+ switch (pdrv) {
+#if HAL_USE_MMC_SPI
+ case MMC:
+ stat = 0;
+ /* It is initialized externally, just reads the status.*/
+ if (blkGetDriverState(&MMCD1) != BLK_READY)
+ stat |= STA_NOINIT;
+ if (mmcIsWriteProtected(&MMCD1))
+ stat |= STA_PROTECT;
+ return stat;
+#elif HAL_USE_SDC
+ case SDC:
+ stat = 0;
+ /* It is initialized externally, just reads the status.*/
+ if (blkGetDriverState(&SDCD1) != BLK_READY)
+ stat |= STA_NOINIT;
+ if (sdcIsWriteProtected(&SDCD1))
+ stat |= STA_PROTECT;
+ return stat;
+#endif
+#if HAL_USBH_USE_MSD
+ case MSDLUN0:
+ stat = 0;
+ /* It is initialized externally, just reads the status.*/
+ if (blkGetDriverState(&MSBLKD[0]) != BLK_READY)
+ stat |= STA_NOINIT;
+ return stat;
+#endif
+ }
+ return STA_NOINIT;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Return Disk Status */
+
+DSTATUS disk_status (
+ BYTE pdrv /* Physical drive nmuber (0..) */
+)
+{
+ DSTATUS stat;
+
+ switch (pdrv) {
+#if HAL_USE_MMC_SPI
+ case MMC:
+ stat = 0;
+ /* It is initialized externally, just reads the status.*/
+ if (blkGetDriverState(&MMCD1) != BLK_READY)
+ stat |= STA_NOINIT;
+ if (mmcIsWriteProtected(&MMCD1))
+ stat |= STA_PROTECT;
+ return stat;
+#elif HAL_USE_SDC
+ case SDC:
+ stat = 0;
+ /* It is initialized externally, just reads the status.*/
+ if (blkGetDriverState(&SDCD1) != BLK_READY)
+ stat |= STA_NOINIT;
+ if (sdcIsWriteProtected(&SDCD1))
+ stat |= STA_PROTECT;
+ return stat;
+#endif
+#if HAL_USBH_USE_MSD
+ case MSDLUN0:
+ stat = 0;
+ /* It is initialized externally, just reads the status.*/
+ if (blkGetDriverState(&MSBLKD[0]) != BLK_READY)
+ stat |= STA_NOINIT;
+ return stat;
+#endif
+ }
+ return STA_NOINIT;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Read Sector(s) */
+
+DRESULT disk_read (
+ BYTE pdrv, /* Physical drive nmuber (0..) */
+ BYTE *buff, /* Data buffer to store read data */
+ DWORD sector, /* Sector address (LBA) */
+ UINT count /* Number of sectors to read (1..255) */
+)
+{
+ switch (pdrv) {
+#if HAL_USE_MMC_SPI
+ case MMC:
+ if (blkGetDriverState(&MMCD1) != BLK_READY)
+ return RES_NOTRDY;
+ if (mmcStartSequentialRead(&MMCD1, sector))
+ return RES_ERROR;
+ while (count > 0) {
+ if (mmcSequentialRead(&MMCD1, buff))
+ return RES_ERROR;
+ buff += MMCSD_BLOCK_SIZE;
+ count--;
+ }
+ if (mmcStopSequentialRead(&MMCD1))
+ return RES_ERROR;
+ return RES_OK;
+#elif HAL_USE_SDC
+ case SDC:
+ if (blkGetDriverState(&SDCD1) != BLK_READY)
+ return RES_NOTRDY;
+ if (sdcRead(&SDCD1, sector, buff, count))
+ return RES_ERROR;
+ return RES_OK;
+#endif
+#if HAL_USBH_USE_MSD
+ case MSDLUN0:
+ /* It is initialized externally, just reads the status.*/
+ if (blkGetDriverState(&MSBLKD[0]) != BLK_READY)
+ return RES_NOTRDY;
+ if (usbhmsdLUNRead(&MSBLKD[0], sector, buff, count))
+ return RES_ERROR;
+ return RES_OK;
+#endif
+ }
+ return RES_PARERR;
+}
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Write Sector(s) */
+
+#if _USE_WRITE
+DRESULT disk_write (
+ BYTE pdrv, /* Physical drive nmuber (0..) */
+ const BYTE *buff, /* Data to be written */
+ DWORD sector, /* Sector address (LBA) */
+ UINT count /* Number of sectors to write (1..255) */
+)
+{
+ switch (pdrv) {
+#if HAL_USE_MMC_SPI
+ case MMC:
+ if (blkGetDriverState(&MMCD1) != BLK_READY)
+ return RES_NOTRDY;
+ if (mmcIsWriteProtected(&MMCD1))
+ return RES_WRPRT;
+ if (mmcStartSequentialWrite(&MMCD1, sector))
+ return RES_ERROR;
+ while (count > 0) {
+ if (mmcSequentialWrite(&MMCD1, buff))
+ return RES_ERROR;
+ buff += MMCSD_BLOCK_SIZE;
+ count--;
+ }
+ if (mmcStopSequentialWrite(&MMCD1))
+ return RES_ERROR;
+ return RES_OK;
+#elif HAL_USE_SDC
+ case SDC:
+ if (blkGetDriverState(&SDCD1) != BLK_READY)
+ return RES_NOTRDY;
+ if (sdcWrite(&SDCD1, sector, buff, count))
+ return RES_ERROR;
+ return RES_OK;
+#endif
+#if HAL_USBH_USE_MSD
+ case MSDLUN0:
+ /* It is initialized externally, just reads the status.*/
+ if (blkGetDriverState(&MSBLKD[0]) != BLK_READY)
+ return RES_NOTRDY;
+ if (usbhmsdLUNWrite(&MSBLKD[0], sector, buff, count))
+ return RES_ERROR;
+ return RES_OK;
+#endif
+ }
+ return RES_PARERR;
+}
+#endif /* _USE_WRITE */
+
+
+
+/*-----------------------------------------------------------------------*/
+/* Miscellaneous Functions */
+
+#if _USE_IOCTL
+DRESULT disk_ioctl (
+ BYTE pdrv, /* Physical drive nmuber (0..) */
+ BYTE cmd, /* Control code */
+ void *buff /* Buffer to send/receive control data */
+)
+{
+ switch (pdrv) {
+#if HAL_USE_MMC_SPI
+ case MMC:
+ switch (cmd) {
+ case CTRL_SYNC:
+ return RES_OK;
+ case GET_SECTOR_SIZE:
+ *((WORD *)buff) = MMCSD_BLOCK_SIZE;
+ return RES_OK;
+#if _USE_ERASE
+ case CTRL_ERASE_SECTOR:
+ mmcErase(&MMCD1, *((DWORD *)buff), *((DWORD *)buff + 1));
+ return RES_OK;
+#endif
+ default:
+ return RES_PARERR;
+ }
+#elif HAL_USE_SDC
+ case SDC:
+ switch (cmd) {
+ case CTRL_SYNC:
+ return RES_OK;
+ case GET_SECTOR_COUNT:
+ *((DWORD *)buff) = mmcsdGetCardCapacity(&SDCD1);
+ return RES_OK;
+ case GET_SECTOR_SIZE:
+ *((WORD *)buff) = MMCSD_BLOCK_SIZE;
+ return RES_OK;
+ case GET_BLOCK_SIZE:
+ *((DWORD *)buff) = 256; /* 512b blocks in one erase block */
+ return RES_OK;
+#if _USE_ERASE
+ case CTRL_ERASE_SECTOR:
+ sdcErase(&SDCD1, *((DWORD *)buff), *((DWORD *)buff + 1));
+ return RES_OK;
+#endif
+ default:
+ return RES_PARERR;
+ }
+#endif
+#if HAL_USBH_USE_MSD
+ case MSDLUN0:
+ switch (cmd) {
+ case CTRL_SYNC:
+ return RES_OK;
+ case GET_SECTOR_COUNT:
+ *((DWORD *)buff) = MSBLKD[0].info.blk_num;
+ return RES_OK;
+ case GET_SECTOR_SIZE:
+ *((WORD *)buff) = MSBLKD[0].info.blk_size;
+ return RES_OK;
+#if _USE_ERASE
+#error "unimplemented yet!"
+// case CTRL_ERASE_SECTOR:
+// ....
+// return RES_OK;
+#endif
+ default:
+ return RES_PARERR;
+ }
+#endif
+ }
+ return RES_PARERR;
+}
+#endif /* _USE_IOCTL */
+
+DWORD get_fattime(void) {
+#if HAL_USE_RTC
+ RTCDateTime timespec;
+
+ rtcGetTime(&RTCD1, &timespec);
+ return rtcConvertDateTimeToFAT(&timespec);
+#else
+ return ((uint32_t)0 | (1 << 16)) | (1 << 21); /* wrong but valid time */
+#endif
+}
+
+