commit
46a0296ed6
|
@ -19,3 +19,7 @@ https://github.com/mabl
|
|||
|
||||
Andrea Zoppi aka TexZK
|
||||
https://github.com/TexZK
|
||||
|
||||
Diego Ismirlian aka dismirlian
|
||||
https://github.com/dismirlian
|
||||
USB Host stack author
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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_ */
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 */
|
||||
|
||||
/** @} */
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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[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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
|
@ -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 msd_result_t scsi_requestsense(USBHMassStorageLUNDriver *lunp, scsi_sense_response_t *resp);
|
||||
|
||||
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_result_t _scsi_perform_transaction(USBHMassStorageLUNDriver *lunp,
|
||||
msd_transaction_t *transaction, void *data) {
|
||||
|
||||
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;
|
||||
|
||||
/* 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_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);
|
||||
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.tres = _msd_transaction(&transaction, lunp, resp);
|
||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||
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);
|
||||
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.tres = _msd_transaction(&transaction, lunp, resp);
|
||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||
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;
|
||||
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.tres = _msd_transaction(&transaction, lunp, resp);
|
||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||
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);
|
||||
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.tres = _msd_transaction(&transaction, lunp, data);
|
||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||
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);
|
||||
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.tres = _msd_transaction(&transaction, lunp, (uint8_t *)data);
|
||||
if (res.tres == MSD_TRANSACTIONRESULT_OK) {
|
||||
res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
|
||||
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);
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
} 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;
|
||||
} else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
|
||||
//TODO: Do reset, etc.
|
||||
uerr("\tTEST UNIT READY: Command Phase Error");
|
||||
goto failed;
|
||||
}
|
||||
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;
|
||||
{
|
||||
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;
|
||||
}
|
||||
lunp->info.blk_size = __REV(u.cap.block_size);
|
||||
lunp->info.blk_num = __REV(u.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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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, ×pec);
|
||||
return rtcConvertDateTimeToFAT(×pec);
|
||||
#else
|
||||
return ((uint32_t)0 | (1 << 16)) | (1 << 21); /* wrong but valid time */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
<folderInfo id="0.1003150841." name="/" resourcePath="">
|
||||
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.748316353" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
|
||||
<targetPlatform id="org.eclipse.cdt.build.core.prefbase.toolchain.748316353.81353447" name=""/>
|
||||
<builder id="org.eclipse.cdt.build.core.settings.default.builder.1044649944" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
|
||||
<builder arguments="-j8" command="make" id="org.eclipse.cdt.build.core.settings.default.builder.1044649944" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
|
||||
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.883535580" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
|
||||
<tool id="org.eclipse.cdt.build.core.settings.holder.97391908" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
|
||||
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.133315636" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
|
||||
|
@ -39,11 +39,26 @@
|
|||
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
|
||||
<project id="STM32F4xx-USB_HOST.null.1232072164" name="STM32F4xx-USB_HOST"/>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
<storageModule moduleId="refreshScope" versionNumber="2">
|
||||
<configuration configurationName="Default">
|
||||
<resource resourceType="PROJECT" workspacePath="/STM32F4xx-USB_HOST"/>
|
||||
</configuration>
|
||||
</storageModule>
|
||||
<storageModule moduleId="scannerConfiguration">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
<scannerConfigBuildInfo instanceId="0.1003150841">
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
|
||||
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
|
||||
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
|
||||
<buildOutputProvider>
|
||||
<openAction enabled="true" filePath="D:/proyectos/ChibiOS-contrib-devel/ChibiOS-Contrib/testhal/STM32/STM32F4xx/USB_HOST/build/ch.elf"/>
|
||||
<parser enabled="true"/>
|
||||
</buildOutputProvider>
|
||||
<scannerInfoProvider id="specsFile">
|
||||
<runAction arguments="-E -P -v -dD "${plugin_state_location}/${specs_file}"" command="arm-none-eabi-gcc" useDefault="true"/>
|
||||
<parser enabled="true"/>
|
||||
</scannerInfoProvider>
|
||||
</profile>
|
||||
</scannerConfigBuildInfo>
|
||||
</storageModule>
|
||||
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
|
||||
</cproject>
|
||||
|
|
|
@ -24,4 +24,16 @@
|
|||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
</natures>
|
||||
<linkedResources>
|
||||
<link>
|
||||
<name>ChibiOS-Contrib-os</name>
|
||||
<type>2</type>
|
||||
<locationURI>$%7BPARENT-5-PROJECT_LOC%7D/ChibiOS-contrib/os</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>ChibiOS-RT-os</name>
|
||||
<type>2</type>
|
||||
<locationURI>$%7BPARENT-5-PROJECT_LOC%7D/ChibiOS-RT/os</locationURI>
|
||||
</link>
|
||||
</linkedResources>
|
||||
</projectDescription>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
# Compiler options here.
|
||||
ifeq ($(USE_OPT),)
|
||||
USE_OPT = -Os -ggdb -fomit-frame-pointer -falign-functions=16
|
||||
USE_OPT = -Og -ggdb3 -fomit-frame-pointer -falign-functions=16
|
||||
endif
|
||||
|
||||
# C specific options here (added to USE_OPT).
|
||||
|
@ -30,7 +30,7 @@ endif
|
|||
|
||||
# Enable this if you want link time optimizations (LTO)
|
||||
ifeq ($(USE_LTO),)
|
||||
USE_LTO = yes
|
||||
USE_LTO = no
|
||||
endif
|
||||
|
||||
# If enabled, this option allows to compile the application in THUMB mode.
|
||||
|
@ -89,7 +89,7 @@ PROJECT = ch
|
|||
CHIBIOS = ../../../../../ChibiOS-RT
|
||||
CHIBIOS_CONTRIB = $(CHIBIOS)/../ChibiOS-Contrib
|
||||
# Startup files.
|
||||
include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk
|
||||
include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_stm32f4xx.mk
|
||||
# HAL-OSAL files (optional).
|
||||
include $(CHIBIOS_CONTRIB)/os/hal/hal.mk
|
||||
include $(CHIBIOS_CONTRIB)/os/hal/ports/STM32/STM32F4xx/platform.mk
|
||||
|
@ -97,12 +97,15 @@ include $(CHIBIOS)/os/hal/boards/ST_STM32F4_DISCOVERY/board.mk
|
|||
include $(CHIBIOS)/os/hal/osal/rt/osal.mk
|
||||
# RTOS files (optional).
|
||||
include $(CHIBIOS)/os/rt/rt.mk
|
||||
include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
|
||||
include $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk
|
||||
# Other files (optional).
|
||||
include $(CHIBIOS)/test/rt/test.mk
|
||||
include $(CHIBIOS)/os/hal/lib/streams/streams.mk
|
||||
include $(CHIBIOS)/os/various/shell/shell.mk
|
||||
include $(CHIBIOS)/os/various/fatfs_bindings/fatfs.mk
|
||||
include $(CHIBIOS_CONTRIB)/os/various/fatfs_bindings/fatfs.mk
|
||||
|
||||
STREAMSSRC = $(CHIBIOS)/os/hal/lib/streams/chprintf.c $(CHIBIOS)/os/hal/lib/streams/memstreams.c
|
||||
STREAMSINC = $(CHIBIOS)/os/hal/lib/streams/
|
||||
SHELLSRC = $(CHIBIOS)/os/various/shell.c
|
||||
SHELLINC = $(CHIBIOS)/os/various/
|
||||
|
||||
# Define linker script file here
|
||||
LDSCRIPT= $(STARTUPLD)/STM32F407xG.ld
|
||||
|
@ -147,8 +150,7 @@ TCSRC =
|
|||
TCPPSRC =
|
||||
|
||||
# List ASM source files here
|
||||
ASMSRC =
|
||||
ASMXSRC = $(STARTUPASM) $(PORTASM) $(OSALASM)
|
||||
ASMSRC = $(STARTUPASM) $(PORTASM) $(OSALASM)
|
||||
|
||||
INCDIR = $(CHIBIOS)/os/license \
|
||||
$(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
|
||||
|
@ -222,5 +224,5 @@ ULIBS =
|
|||
# End of user defines
|
||||
##############################################################################
|
||||
|
||||
RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC
|
||||
RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC
|
||||
include $(RULESPATH)/rules.mk
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
/*-----------------------------------------------------------------------/
|
||||
/ Low level disk interface modlue include file (C)ChaN, 2014 /
|
||||
/-----------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _DISKIO_DEFINED
|
||||
#define _DISKIO_DEFINED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define _USE_WRITE 1 /* 1: Enable disk_write function */
|
||||
#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */
|
||||
|
||||
#include "integer.h"
|
||||
|
||||
|
||||
/* Status of Disk Functions */
|
||||
typedef BYTE DSTATUS;
|
||||
|
||||
/* Results of Disk Functions */
|
||||
typedef enum {
|
||||
RES_OK = 0, /* 0: Successful */
|
||||
RES_ERROR, /* 1: R/W Error */
|
||||
RES_WRPRT, /* 2: Write Protected */
|
||||
RES_NOTRDY, /* 3: Not Ready */
|
||||
RES_PARERR /* 4: Invalid Parameter */
|
||||
} DRESULT;
|
||||
|
||||
|
||||
/*---------------------------------------*/
|
||||
/* Prototypes for disk control functions */
|
||||
|
||||
|
||||
DSTATUS disk_initialize (BYTE pdrv);
|
||||
DSTATUS disk_status (BYTE pdrv);
|
||||
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
|
||||
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
|
||||
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
|
||||
|
||||
|
||||
/* Disk Status Bits (DSTATUS) */
|
||||
|
||||
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||
#define STA_PROTECT 0x04 /* Write protected */
|
||||
|
||||
|
||||
/* Command code for disk_ioctrl fucntion */
|
||||
|
||||
/* Generic command (Used by FatFs) */
|
||||
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
|
||||
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
|
||||
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
|
||||
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
|
||||
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
|
||||
|
||||
/* Generic command (Not used by FatFs) */
|
||||
#define CTRL_POWER 5 /* Get/Set power status */
|
||||
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
|
||||
#define CTRL_EJECT 7 /* Eject media */
|
||||
#define CTRL_FORMAT 8 /* Create physical format on the media */
|
||||
|
||||
/* MMC/SDC specific ioctl command */
|
||||
#define MMC_GET_TYPE 10 /* Get card type */
|
||||
#define MMC_GET_CSD 11 /* Get CSD */
|
||||
#define MMC_GET_CID 12 /* Get CID */
|
||||
#define MMC_GET_OCR 13 /* Get OCR */
|
||||
#define MMC_GET_SDSTAT 14 /* Get SD status */
|
||||
|
||||
/* ATA/CF specific ioctl command */
|
||||
#define ATA_GET_REV 20 /* Get F/W revision */
|
||||
#define ATA_GET_MODEL 21 /* Get model name */
|
||||
#define ATA_GET_SN 22 /* Get serial number */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,143 +0,0 @@
|
|||
/*-----------------------------------------------------------------------*/
|
||||
/* 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"
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Correspondence between physical drive number and physical drive. */
|
||||
#define MSDLUN0 0
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Inidialize a Drive */
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber (0..) */
|
||||
)
|
||||
{
|
||||
DSTATUS stat;
|
||||
|
||||
switch (pdrv) {
|
||||
case MSDLUN0:
|
||||
stat = 0;
|
||||
/* It is initialized externally, just reads the status.*/
|
||||
if (blkGetDriverState(&MSBLKD[0]) != BLK_READY)
|
||||
stat |= STA_NOINIT;
|
||||
return stat;
|
||||
}
|
||||
return STA_NOINIT;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Return Disk Status */
|
||||
|
||||
DSTATUS disk_status (
|
||||
BYTE pdrv /* Physical drive nmuber (0..) */
|
||||
)
|
||||
{
|
||||
DSTATUS stat;
|
||||
|
||||
switch (pdrv) {
|
||||
case MSDLUN0:
|
||||
stat = 0;
|
||||
/* It is initialized externally, just reads the status.*/
|
||||
if (blkGetDriverState(&MSBLKD[0]) != BLK_READY)
|
||||
stat |= STA_NOINIT;
|
||||
return stat;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
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;
|
||||
default:
|
||||
return RES_PARERR;
|
||||
}
|
||||
}
|
||||
return RES_PARERR;
|
||||
}
|
||||
#endif /* _USE_IOCTL */
|
||||
|
||||
DWORD get_fattime(void) {
|
||||
return ((uint32_t)0 | (1 << 16)) | (1 << 21); /* wrong but valid time */
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,342 +0,0 @@
|
|||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module include file R0.10b (C)ChaN, 2014
|
||||
/----------------------------------------------------------------------------/
|
||||
/ FatFs module is a generic FAT file system module for small embedded systems.
|
||||
/ This is a free software that opened for education, research and commercial
|
||||
/ developments under license policy of following terms.
|
||||
/
|
||||
/ Copyright (C) 2014, ChaN, all right reserved.
|
||||
/
|
||||
/ * The FatFs module is a free software and there is NO WARRANTY.
|
||||
/ * No restriction on use. You can use, modify and redistribute it for
|
||||
/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
|
||||
/ * Redistributions of source code must retain the above copyright notice.
|
||||
/
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _FATFS
|
||||
#define _FATFS 8051 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "integer.h" /* Basic integer types */
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if _FATFS != _FFCONF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if _MULTI_PARTITION /* Multiple partition configuration */
|
||||
typedef struct {
|
||||
BYTE pd; /* Physical drive number */
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
||||
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
|
||||
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
|
||||
|
||||
#else /* Single partition configuration */
|
||||
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
|
||||
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of path name strings on FatFs API */
|
||||
|
||||
#if _LFN_UNICODE /* Unicode string */
|
||||
#if !_USE_LFN
|
||||
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
||||
#endif
|
||||
#ifndef _INC_TCHAR
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L ## x
|
||||
#define _TEXT(x) L ## x
|
||||
#endif
|
||||
|
||||
#else /* ANSI/OEM string */
|
||||
#ifndef _INC_TCHAR
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* File system object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
|
||||
BYTE drv; /* Physical drive number */
|
||||
BYTE csize; /* Sectors per cluster (1,2,4...128) */
|
||||
BYTE n_fats; /* Number of FAT copies (1 or 2) */
|
||||
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||
WORD id; /* File system mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
#if _MAX_SS != _MIN_SS
|
||||
WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
|
||||
#endif
|
||||
#if _FS_REENTRANT
|
||||
_SYNC_t sobj; /* Identifier of sync object */
|
||||
#endif
|
||||
#if !_FS_READONLY
|
||||
DWORD last_clust; /* Last allocated cluster */
|
||||
DWORD free_clust; /* Number of free clusters */
|
||||
#endif
|
||||
#if _FS_RPATH
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#endif
|
||||
DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */
|
||||
DWORD fsize; /* Sectors per FAT */
|
||||
DWORD volbase; /* Volume start sector */
|
||||
DWORD fatbase; /* FAT start sector */
|
||||
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
|
||||
DWORD database; /* Data start sector */
|
||||
DWORD winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the related file system object (**do not change order**) */
|
||||
WORD id; /* Owner file system mount ID (**do not change order**) */
|
||||
BYTE flag; /* Status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
DWORD fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD fsize; /* File size */
|
||||
DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
|
||||
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
|
||||
DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !_FS_READONLY
|
||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
||||
#endif
|
||||
#if _USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
|
||||
#endif
|
||||
#if _FS_LOCK
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
#if !_FS_TINY
|
||||
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */
|
||||
WORD id; /* Owner file system mount ID (**do not change order**) */
|
||||
WORD index; /* Current read/write index number */
|
||||
DWORD sclust; /* Table start cluster (0:Root dir) */
|
||||
DWORD clust; /* Current cluster */
|
||||
DWORD sect; /* Current sector */
|
||||
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
|
||||
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
|
||||
#if _FS_LOCK
|
||||
UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
#if _USE_LFN
|
||||
WCHAR* lfn; /* Pointer to the LFN working buffer */
|
||||
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
|
||||
#endif
|
||||
} DIR;
|
||||
|
||||
|
||||
|
||||
/* File status structure (FILINFO) */
|
||||
|
||||
typedef struct {
|
||||
DWORD fsize; /* File size */
|
||||
WORD fdate; /* Last modified date */
|
||||
WORD ftime; /* Last modified time */
|
||||
BYTE fattrib; /* Attribute */
|
||||
TCHAR fname[13]; /* Short file name (8.3 format) */
|
||||
#if _USE_LFN
|
||||
TCHAR* lfname; /* Pointer to the LFN buffer */
|
||||
UINT lfsize; /* Size of LFN buffer in TCHAR */
|
||||
#endif
|
||||
} FILINFO;
|
||||
|
||||
|
||||
|
||||
/* File function return code (FRESULT) */
|
||||
|
||||
typedef enum {
|
||||
FR_OK = 0, /* (0) Succeeded */
|
||||
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||
FR_INT_ERR, /* (2) Assertion failed */
|
||||
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||
FR_NO_FILE, /* (4) Could not find the file */
|
||||
FR_NO_PATH, /* (5) Could not find the path */
|
||||
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
|
||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* FatFs module application interface */
|
||||
|
||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
|
||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */
|
||||
FRESULT f_truncate (FIL* fp); /* Truncate file */
|
||||
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
|
||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||
FRESULT f_chmod (const TCHAR* path, BYTE value, BYTE mask); /* Change attribute of the file/dir */
|
||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */
|
||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
|
||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||
|
||||
#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
|
||||
#define f_error(fp) ((fp)->err)
|
||||
#define f_tell(fp) ((fp)->fptr)
|
||||
#define f_size(fp) ((fp)->fsize)
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Additional user defined functions */
|
||||
|
||||
/* RTC function */
|
||||
#if !_FS_READONLY
|
||||
DWORD get_fattime (void);
|
||||
#endif
|
||||
|
||||
/* Unicode support functions */
|
||||
#if _USE_LFN /* Unicode - OEM code conversion */
|
||||
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
|
||||
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
|
||||
#if _USE_LFN == 3 /* Memory functions */
|
||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||
void ff_memfree (void* mblock); /* Free memory block */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Sync functions */
|
||||
#if _FS_REENTRANT
|
||||
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
|
||||
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
|
||||
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
|
||||
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Flags and offset address */
|
||||
|
||||
|
||||
/* File access control and file status flags (FIL.flag) */
|
||||
|
||||
#define FA_READ 0x01
|
||||
#define FA_OPEN_EXISTING 0x00
|
||||
|
||||
#if !_FS_READONLY
|
||||
#define FA_WRITE 0x02
|
||||
#define FA_CREATE_NEW 0x04
|
||||
#define FA_CREATE_ALWAYS 0x08
|
||||
#define FA_OPEN_ALWAYS 0x10
|
||||
#define FA__WRITTEN 0x20
|
||||
#define FA__DIRTY 0x40
|
||||
#endif
|
||||
|
||||
|
||||
/* FAT sub type (FATFS.fs_type) */
|
||||
|
||||
#define FS_FAT12 1
|
||||
#define FS_FAT16 2
|
||||
#define FS_FAT32 3
|
||||
|
||||
|
||||
/* File attribute bits for directory entry */
|
||||
|
||||
#define AM_RDO 0x01 /* Read only */
|
||||
#define AM_HID 0x02 /* Hidden */
|
||||
#define AM_SYS 0x04 /* System */
|
||||
#define AM_VOL 0x08 /* Volume label */
|
||||
#define AM_LFN 0x0F /* LFN entry */
|
||||
#define AM_DIR 0x10 /* Directory */
|
||||
#define AM_ARC 0x20 /* Archive */
|
||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
||||
|
||||
|
||||
/* Fast seek feature */
|
||||
#define CREATE_LINKMAP 0xFFFFFFFF
|
||||
|
||||
|
||||
|
||||
/*--------------------------------*/
|
||||
/* Multi-byte word access macros */
|
||||
|
||||
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
|
||||
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
|
||||
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
|
||||
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
|
||||
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
|
||||
#else /* Use byte-by-byte access to the FAT structure */
|
||||
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
|
||||
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
|
||||
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
|
||||
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FATFS */
|
|
@ -8,7 +8,6 @@
|
|||
#ifndef _FFCONF
|
||||
#define _FFCONF 8051 /* Revision ID */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Functions and Buffer Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
@ -92,7 +91,7 @@
|
|||
/ 1 - ASCII (Valid for only non-LFN configuration) */
|
||||
|
||||
|
||||
#define _USE_LFN 3 /* 0 to 3 */
|
||||
#define _USE_LFN 0 /* 0 to 3 */
|
||||
#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
|
||||
/* The _USE_LFN option switches the LFN feature.
|
||||
/
|
||||
|
|
|
@ -91,13 +91,13 @@
|
|||
#define HAL_USBH_DEVICE_ADDRESS_STABILIZATION 20
|
||||
|
||||
/* MSD */
|
||||
#define HAL_USBH_USE_MSD 1
|
||||
#define HAL_USBH_USE_MSD TRUE
|
||||
|
||||
#define HAL_USBHMSD_MAX_LUNS 1
|
||||
#define HAL_USBHMSD_MAX_INSTANCES 1
|
||||
|
||||
/* IAD */
|
||||
#define HAL_USBH_USE_FTDI 1
|
||||
/* FTDI */
|
||||
#define HAL_USBH_USE_FTDI TRUE
|
||||
|
||||
#define HAL_USBHFTDI_MAX_PORTS 1
|
||||
#define HAL_USBHFTDI_MAX_INSTANCES 1
|
||||
|
@ -107,61 +107,85 @@
|
|||
#define HAL_USBHFTDI_DEFAULT_XON 0x11
|
||||
#define HAL_USBHFTDI_DEFAULT_XOFF 0x13
|
||||
|
||||
/* AOA */
|
||||
#define HAL_USBH_USE_AOA TRUE
|
||||
|
||||
/* IAD */
|
||||
#define HAL_USBH_USE_IAD 0
|
||||
#define HAL_USBHAOA_MAX_INSTANCES 1
|
||||
/* Uncomment this if you need a filter for AOA devices:
|
||||
* #define HAL_USBHAOA_FILTER_CALLBACK _try_aoa
|
||||
*/
|
||||
#define HAL_USBHAOA_DEFAULT_MANUFACTURER "Diego MFG & Co."
|
||||
#define HAL_USBHAOA_DEFAULT_MODEL "Diego's device"
|
||||
#define HAL_USBHAOA_DEFAULT_DESCRIPTION "Description of this device..."
|
||||
#define HAL_USBHAOA_DEFAULT_VERSION "1.0"
|
||||
#define HAL_USBHAOA_DEFAULT_URI NULL
|
||||
#define HAL_USBHAOA_DEFAULT_SERIAL NULL
|
||||
#define HAL_USBHAOA_DEFAULT_AUDIO_MODE USBHAOA_AUDIO_MODE_DISABLED
|
||||
|
||||
/* UVC */
|
||||
#define HAL_USBH_USE_UVC 0
|
||||
#define HAL_USBH_USE_UVC TRUE
|
||||
|
||||
#define HAL_USBHUVC_MAX_INSTANCES 1
|
||||
#define HAL_USBHUVC_MAX_MAILBOX_SZ 70
|
||||
#define HAL_USBHUVC_WORK_RAM_SIZE 20000
|
||||
#define HAL_USBHUVC_STATUS_PACKETS_COUNT 10
|
||||
|
||||
/* HID */
|
||||
#define HAL_USBH_USE_HID TRUE
|
||||
#define HAL_USBHHID_MAX_INSTANCES 2
|
||||
#define HAL_USBHHID_USE_INTERRUPT_OUT FALSE
|
||||
|
||||
/* HUB */
|
||||
#define HAL_USBH_USE_HUB 1
|
||||
#define HAL_USBH_USE_HUB TRUE
|
||||
|
||||
#define HAL_USBHHUB_MAX_INSTANCES 1
|
||||
#define HAL_USBHHUB_MAX_PORTS 6
|
||||
|
||||
|
||||
/* debug */
|
||||
#define USBH_DEBUG_ENABLE 1
|
||||
#define USBH_DEBUG_ENABLE TRUE
|
||||
#define USBH_DEBUG_USBHD USBHD1
|
||||
#define USBH_DEBUG_SD SD2
|
||||
#define USBH_DEBUG_BUFFER 25000
|
||||
|
||||
#define USBH_DEBUG_ENABLE_TRACE 0
|
||||
#define USBH_DEBUG_ENABLE_INFO 1
|
||||
#define USBH_DEBUG_ENABLE_WARNINGS 1
|
||||
#define USBH_DEBUG_ENABLE_ERRORS 1
|
||||
#define USBH_DEBUG_ENABLE_TRACE FALSE
|
||||
#define USBH_DEBUG_ENABLE_INFO TRUE
|
||||
#define USBH_DEBUG_ENABLE_WARNINGS TRUE
|
||||
#define USBH_DEBUG_ENABLE_ERRORS TRUE
|
||||
|
||||
#define USBH_LLD_DEBUG_ENABLE_TRACE 0
|
||||
#define USBH_LLD_DEBUG_ENABLE_INFO 1
|
||||
#define USBH_LLD_DEBUG_ENABLE_WARNINGS 1
|
||||
#define USBH_LLD_DEBUG_ENABLE_ERRORS 1
|
||||
#define USBH_LLD_DEBUG_ENABLE_TRACE FALSE
|
||||
#define USBH_LLD_DEBUG_ENABLE_INFO TRUE
|
||||
#define USBH_LLD_DEBUG_ENABLE_WARNINGS TRUE
|
||||
#define USBH_LLD_DEBUG_ENABLE_ERRORS TRUE
|
||||
|
||||
#define USBHHUB_DEBUG_ENABLE_TRACE 0
|
||||
#define USBHHUB_DEBUG_ENABLE_INFO 1
|
||||
#define USBHHUB_DEBUG_ENABLE_WARNINGS 1
|
||||
#define USBHHUB_DEBUG_ENABLE_ERRORS 1
|
||||
#define USBHHUB_DEBUG_ENABLE_TRACE FALSE
|
||||
#define USBHHUB_DEBUG_ENABLE_INFO TRUE
|
||||
#define USBHHUB_DEBUG_ENABLE_WARNINGS TRUE
|
||||
#define USBHHUB_DEBUG_ENABLE_ERRORS TRUE
|
||||
|
||||
#define USBHMSD_DEBUG_ENABLE_TRACE 0
|
||||
#define USBHMSD_DEBUG_ENABLE_INFO 1
|
||||
#define USBHMSD_DEBUG_ENABLE_WARNINGS 1
|
||||
#define USBHMSD_DEBUG_ENABLE_ERRORS 1
|
||||
#define USBHMSD_DEBUG_ENABLE_TRACE FALSE
|
||||
#define USBHMSD_DEBUG_ENABLE_INFO TRUE
|
||||
#define USBHMSD_DEBUG_ENABLE_WARNINGS TRUE
|
||||
#define USBHMSD_DEBUG_ENABLE_ERRORS TRUE
|
||||
|
||||
#define USBHUVC_DEBUG_ENABLE_TRACE 0
|
||||
#define USBHUVC_DEBUG_ENABLE_INFO 1
|
||||
#define USBHUVC_DEBUG_ENABLE_WARNINGS 1
|
||||
#define USBHUVC_DEBUG_ENABLE_ERRORS 1
|
||||
#define USBHUVC_DEBUG_ENABLE_TRACE FALSE
|
||||
#define USBHUVC_DEBUG_ENABLE_INFO TRUE
|
||||
#define USBHUVC_DEBUG_ENABLE_WARNINGS TRUE
|
||||
#define USBHUVC_DEBUG_ENABLE_ERRORS TRUE
|
||||
|
||||
#define USBHFTDI_DEBUG_ENABLE_TRACE 0
|
||||
#define USBHFTDI_DEBUG_ENABLE_INFO 1
|
||||
#define USBHFTDI_DEBUG_ENABLE_WARNINGS 1
|
||||
#define USBHFTDI_DEBUG_ENABLE_ERRORS 1
|
||||
#define USBHFTDI_DEBUG_ENABLE_TRACE FALSE
|
||||
#define USBHFTDI_DEBUG_ENABLE_INFO TRUE
|
||||
#define USBHFTDI_DEBUG_ENABLE_WARNINGS TRUE
|
||||
#define USBHFTDI_DEBUG_ENABLE_ERRORS TRUE
|
||||
|
||||
#define USBHAOA_DEBUG_ENABLE_TRACE FALSE
|
||||
#define USBHAOA_DEBUG_ENABLE_INFO TRUE
|
||||
#define USBHAOA_DEBUG_ENABLE_WARNINGS TRUE
|
||||
#define USBHAOA_DEBUG_ENABLE_ERRORS TRUE
|
||||
|
||||
#define USBHHID_DEBUG_ENABLE_TRACE FALSE
|
||||
#define USBHHID_DEBUG_ENABLE_INFO TRUE
|
||||
#define USBHHID_DEBUG_ENABLE_WARNINGS TRUE
|
||||
#define USBHHID_DEBUG_ENABLE_ERRORS TRUE
|
||||
|
||||
/*===========================================================================*/
|
||||
/* FSMCNAND driver related settings. */
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*-------------------------------------------*/
|
||||
/* Integer type definitions for FatFs module */
|
||||
/*-------------------------------------------*/
|
||||
|
||||
#ifndef _FF_INTEGER
|
||||
#define _FF_INTEGER
|
||||
|
||||
#ifdef _WIN32 /* FatFs development platform */
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#else /* Embedded platform */
|
||||
|
||||
/* This type MUST be 8 bit */
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* These types MUST be 16 bit */
|
||||
typedef short SHORT;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned short WCHAR;
|
||||
|
||||
/* These types MUST be 16 bit or 32 bit */
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
|
||||
/* These types MUST be 32 bit */
|
||||
typedef long LONG;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue