vxkernel - v0.7.0-4 : add USB request handling (WIP)
*add* > [vhex/display] | [text] add va_list version of dtext() and dprint() > [vhex/defs] | [types] add x_union_alone > [vhex/usb] | [request] add USB request (WIP) | [pipe] add USB pipe API (WIP) | [dcp] add USB DCP API (WIP) | [macros] add interrupt clearing helper | [descriptor] add main USB descriptors *update* > [vhex/defs] | [attributes] rename VPACKEDENUM -> VPACKED_ALONE > [vhex/usb] | [interrupt] enable setup interruptions | [open] perform USB device configuration check *fix* > [vhex/defs] | [call] fix last argument injection > [vhex/usb] | [macros] fix delay for register sync. | [open] force-clear interrupt flags befor enabling interruption
This commit is contained in:
parent
42c3fabb34
commit
c6aa4b5ac4
|
@ -20,7 +20,7 @@
|
|||
access sizes silently fail - honestly you don't want this to happen */
|
||||
#define VPACKED(x) __attribute__((packed, aligned(x)))
|
||||
/* Packed enumerations */
|
||||
#define VPACKEDENUM __attribute__((packed))
|
||||
#define VPACKED_ALONE __attribute__((packed))
|
||||
/* Transparent unions */
|
||||
#define VTRANSPARENT __attribute__((transparent_union))
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ typedef struct vhex_call vhex_call_t;
|
|||
|
||||
/* VHEX_CALL(): Build an callback from function and arguments */
|
||||
#define VHEX_CALL(fct, ...) \
|
||||
((vhex_call_t){ \
|
||||
((vhex_call_t){ \
|
||||
.function = (void*)fct, \
|
||||
.args = { __VA_OPT__(VHEX_CALL_ARGS1(__VA_ARGS__)) } \
|
||||
})
|
||||
|
@ -78,7 +78,7 @@ typedef struct vhex_call vhex_call_t;
|
|||
"VHEX_CALL: too many arguments (maximum 4)" \
|
||||
); \
|
||||
) \
|
||||
(vhex_call_arg_t)(a4); \
|
||||
VHEX_CALL_ARG(a4) \
|
||||
})
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -45,4 +45,26 @@ typedef unsigned int uint;
|
|||
struct { fields } VPACKED(4); \
|
||||
} VPACKED(4) name
|
||||
|
||||
|
||||
/* byte_union() - same as `byte_union()` but without aligment */
|
||||
#define byte_union_alone(name, fields) \
|
||||
union { \
|
||||
uint8_t byte; \
|
||||
struct { fields } VPACKED_ALONE;\
|
||||
} VPACKED_ALONE name
|
||||
|
||||
/* word_union_alone() - same as `word_union()` but without aligment */
|
||||
#define word_union_alone(name, fields) \
|
||||
union { \
|
||||
uint16_t word; \
|
||||
struct { fields } VPACKED_ALONE;\
|
||||
} VPACKED_ALONE name
|
||||
|
||||
/* lword_union_alone() - same as `lword_union()` but without aligment */
|
||||
#define lword_union_alone(name, fields) \
|
||||
union { \
|
||||
uint32_t lword; \
|
||||
struct { fields } VPACKED_ALONE;\
|
||||
} VPACKED_ALONE name
|
||||
|
||||
#endif /*__VHEX_DEFS_TYPES__*/
|
||||
|
|
|
@ -34,10 +34,25 @@ extern did_t dprint_opt(
|
|||
int x, int y,
|
||||
int fg, int bg,
|
||||
int align,
|
||||
char const * const str, ...
|
||||
char const * const str,
|
||||
...
|
||||
);
|
||||
|
||||
/* dprint() : display formated text */
|
||||
extern did_t dprint(int x, int y, int fg, char const * const text, ...);
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* dvprint_opt(): Display a string of text */
|
||||
extern did_t dvprint_opt(
|
||||
int x, int y,
|
||||
int fg, int bg,
|
||||
int align,
|
||||
char const *text,
|
||||
va_list ap
|
||||
);
|
||||
|
||||
/* dvprint() : display formated text (vargs version) */
|
||||
extern did_t dvprint(int x, int y, int fg, char const * const text, va_list ap);
|
||||
|
||||
#endif /* __VHEX_DISPLAY_TEXT_RENDER__ */
|
||||
|
|
|
@ -433,6 +433,25 @@ union __sh7305_usb_uponcr
|
|||
// Kernel-level USB API
|
||||
//---
|
||||
|
||||
/* SH7305_USB_DVSQ_* - device state value */
|
||||
enum {
|
||||
SH7305_USB_DVSQ_POWERED = 0,
|
||||
SH7305_USB_DVSQ_DEFAULT = 1,
|
||||
SH7305_USB_DVSQ_ADDRESS = 2,
|
||||
SH7305_USB_DVSQ_CONFIGURED = 3,
|
||||
};
|
||||
/* SH&SH7305_USB_REQT_* - device request value */
|
||||
enum {
|
||||
SH7305_USB_REQT_GET_STATUS = 0x00,
|
||||
SH7305_USB_REQT_CLEAR_FEATURE = 0x01,
|
||||
SH7305_USB_REQT_SET_FEATURE = 0x03,
|
||||
SH7305_USB_REQT_SET_ADDRESS = 0x05,
|
||||
SH7305_USB_REQT_GET_DESCRIPTOR = 0x06,
|
||||
SH7305_USB_REQT_SET_DESCRIPTOR = 0x07,
|
||||
SH7305_USB_REQT_GET_CONFIGURATION = 0x08,
|
||||
SH7305_USB_REQT_SET_CONFIGURATION = 0x09,
|
||||
};
|
||||
|
||||
/* sh7305_usb_hpowered() : check if the USB module is powered */
|
||||
extern bool sh7305_usb_hpowered(void);
|
||||
|
||||
|
@ -442,24 +461,40 @@ extern int sh7305_usb_hpoweron(void);
|
|||
/* sh7305_usb_hpoweroff() : power off the USB module */
|
||||
extern int sh7305_usb_hpoweroff(void);
|
||||
|
||||
/* sh7305_usb_open() : power on the module and setup USB module */
|
||||
extern int sh7305_usb_open(void *_, void *__);
|
||||
|
||||
/* sh7305_usb_interrupt_handler() : interrupt handler invoked by hardware */
|
||||
extern void sh7305_usb_interrupt_handler(void);
|
||||
|
||||
/* sh7305_usb_request_handle() : handle USB request */
|
||||
extern void sh7305_usb_request_handle(void);
|
||||
|
||||
#include <vhex/usb/device.h>
|
||||
|
||||
/* sh7305_usb_open() : power on the module and setup USB module */
|
||||
extern int sh7305_usb_open(struct usb_full_device *device);
|
||||
|
||||
/* sh7305_configuration_resolve() : check and resolve USB configuration */
|
||||
extern int sh7305_usb_configuration_resolve(struct usb_full_device *device);
|
||||
|
||||
/* sh7305_pipe_find() : try to find a pipe */
|
||||
extern int sh7305_usb_pipe_find(int type);
|
||||
|
||||
/* sh7305_usb_dcp_write() : send data through DCP pipe */
|
||||
extern int sh7305_usb_dcp_write(void *buffer, size_t n);
|
||||
|
||||
//---
|
||||
// Utils
|
||||
//---
|
||||
|
||||
#include <vhex/driver/mpu/sh/sh7305/tmu.h>
|
||||
#include <vhex/usb/logger.h>
|
||||
#include <vhex/defs/call.h>
|
||||
|
||||
/* SH7305_USB_REG_SYN() : activly wait the condition. */
|
||||
#define SH7305_USB_REG_SYNC(condition) ({ \
|
||||
volatile int __trigger = 0; \
|
||||
int __timer = sh7305_tmu_configure( \
|
||||
1000000000 /*µs*/, \
|
||||
100000 /*µs*/, \
|
||||
VHEX_CALL_SET_STOP(&__trigger) \
|
||||
); \
|
||||
if(__timer >= 0) { timer_start(__timer); } \
|
||||
|
@ -476,4 +511,12 @@ extern void sh7305_usb_interrupt_handler(void);
|
|||
} \
|
||||
})
|
||||
|
||||
/* SH7305_USB_INTSTS0_CLEAR() : clear interrup flags */
|
||||
#define SH7305_USB_INTSTS0_CLEAR(field_name) ({ \
|
||||
__typeof__(SH7305_USB.INTSTS0) __intsts0 = { .word = 0xffff }; \
|
||||
__intsts0.field_name = 0; \
|
||||
do SH7305_USB.INTSTS0 = __intsts0; \
|
||||
while(SH7305_USB.INTSTS0.field_name != 0); \
|
||||
})
|
||||
|
||||
#endif /*__VHEX_MPU_SH7305_USB_ */
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef __VHEX_USB_DESCRIPTOR_CONFIGURATION_H__
|
||||
#define __VHEX_USB_DESCRIPTOR_CONFIGURATION_H__ 1
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
/* usb_descriptor_configuration - USB Configuration Descriptor struct */
|
||||
struct usb_descriptor_configuration {
|
||||
uint8_t bLengh; /* size of this descriptor in bytes */
|
||||
uint8_t bDescriptorType; /* USB_DESCRIPTOR_CONFIG */
|
||||
uint16_t wTotalLengh; /* total lengh of configuration data */
|
||||
uint8_t bNumInterfaces; /* number of interface */
|
||||
uint8_t bConfigurationValue; /* configuration index (start at 1!) */
|
||||
uint8_t iConfiguration; /* index of string desc. */
|
||||
|
||||
/* Configuration characteristics
|
||||
* @notes
|
||||
* - power 1=self-powered
|
||||
* - wakeup 1=remote wakeup support */
|
||||
byte_union_alone(bmAttributes,
|
||||
uint8_t : 1;
|
||||
uint8_t power : 1;
|
||||
uint8_t wakeup : 1;
|
||||
uint8_t : 4;
|
||||
);
|
||||
|
||||
/* Maximum power that USB should provide
|
||||
* @notes
|
||||
* - only provided if bmAttributes.power=1
|
||||
* - exposed as bMaxPower=1 -> 2mA (ex: bMaxPower=50 -> 100mA) */
|
||||
uint8_t bMaxPower;
|
||||
} VPACKED_ALONE;
|
||||
|
||||
#include <vhex/usb/descriptor/types.h>
|
||||
#include <vhex/usb/utils.h>
|
||||
|
||||
/* USB_DECLARE_DESC_CONF - helper to declare configuration descriptor */
|
||||
#define USB_DECLARE_DESC_CONF(name, ...) \
|
||||
struct usb_descriptor_configuration name = \
|
||||
USB_DECLARE_DESC_CONF_RAW(__VA_ARGS__)
|
||||
|
||||
/* USB_DECLARE_DESC_CONF_RAW - helper to declare default content */
|
||||
#define USB_DECLARE_DESC_CONF_RAW(...) \
|
||||
{ \
|
||||
.bLengh = sizeof(struct usb_descriptor_configuration), \
|
||||
.bDescriptorType = USB_DESCRIPTOR_CONFIGURATION, \
|
||||
__VA_ARGS__ \
|
||||
}
|
||||
|
||||
#endif /* __VHEX_USB_DESCRIPTOR_CONFIGURATION_H__ */
|
|
@ -0,0 +1,41 @@
|
|||
#ifndef __VHEX_USB_DESCRIPTOR_DEVICE_H__
|
||||
#define __VHEX_USB_DESCRIPTOR_DEVICE_H__ 1
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
/* usb_descriptor_device - USB Device Descriptor struct */
|
||||
struct usb_descriptor_device {
|
||||
uint8_t bLengh; /* size of this descriptor in bytes */
|
||||
uint8_t bDescriptorType; /* descriptor type (USB_DESCRIPTOR_DEVICE) */
|
||||
uint16_t bcdUSB; /* USB release number in bin. (0x210 -> 2.1) */
|
||||
uint8_t bDeviceClass; /* class code */
|
||||
uint8_t bDeviceSubClass; /* subclass code */
|
||||
uint8_t bDeviceProtocol; /* protocol code */
|
||||
uint8_t bMaxPacketSize0; /* packet size of endpoint 0 */
|
||||
uint16_t idVendor; /* vendor ID (assigned by USB-IF) */
|
||||
uint16_t idProduct; /* product ID (assigned by manufacturer) */
|
||||
uint16_t bcdDevice; /* device release version (0x220 -> 2.220) */
|
||||
uint8_t iManufacturer; /* index of string descr. for Manufacturer */
|
||||
uint8_t iProduct; /* index of string descr. for product */
|
||||
uint8_t iSerialNumber; /* index of string descr. for serial number */
|
||||
uint8_t bNumConfigurations;/* number of possible configuration */
|
||||
} VPACKED_ALONE;
|
||||
|
||||
#include <vhex/usb/descriptor/types.h>
|
||||
#include <vhex/usb/utils.h>
|
||||
|
||||
/* USB_DECLARE_DESC_DEV - helper to declare device descriptor */
|
||||
#define USB_DECLARE_DESC_DEVICE(name, ...) \
|
||||
struct usb_descriptor_device name = \
|
||||
USB_DECLARE_DESC_DEVICE_RAW(__VA_ARGS__)
|
||||
|
||||
/* USB_DECLARE_DESC_DEVICE_RAW - helper to declare default content */
|
||||
#define USB_DECLARE_DESC_DEVICE_RAW(...) \
|
||||
{ \
|
||||
.bLengh = sizeof(struct usb_descriptor_device), \
|
||||
.bDescriptorType = USB_DESCRIPTOR_DEVICE, \
|
||||
.bcdUSB = USB_WORD_TO(0x200), \
|
||||
__VA_ARGS__ \
|
||||
}
|
||||
|
||||
#endif /* __VHEX_USB_DESCRIPTOR_DEVICE_H__ */
|
|
@ -0,0 +1,62 @@
|
|||
#ifndef __VHEX_USB_DESCRIPTOR_ENDPOINT_H__
|
||||
#define __VHEX_USB_DESCRIPTOR_ENDPOINT_H__ 1
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
/* usb_descriptor_endpoint - USB Endpoint Descriptor struct */
|
||||
struct usb_descriptor_endpoint {
|
||||
uint8_t bLengh; /* size of this descriptor in bytes */
|
||||
uint8_t bDescriptorType; /* descriptor type (USB_DESCRIPTOR_DEVICE) */
|
||||
|
||||
/* bEndpointAddress - Endpoint address configuration
|
||||
* @notes
|
||||
* - dir 0=OUT, 1=IN
|
||||
* - number the endpoint number */
|
||||
byte_union_alone(bEndpointAddress,
|
||||
uint8_t dir : 1;
|
||||
uint8_t : 3;
|
||||
uint8_t number : 4;
|
||||
);
|
||||
|
||||
/* bmAttributes - Endpoint configuration
|
||||
* @notes
|
||||
* - usage usage type (Data, Feedback, Implicit feedback)
|
||||
* - sync synchronization type (No sync., Async., Adaptive, Sync.)
|
||||
* - trans transfert type (Control, Isochronous, bulk, Interrupt) */
|
||||
byte_union_alone(bmAttributes,
|
||||
uint8_t : 2;
|
||||
uint8_t usage : 2;
|
||||
uint8_t sync : 2;
|
||||
uint8_t trans : 2;
|
||||
);
|
||||
|
||||
/* wPacketSize - Maximum packet size for this endpoint
|
||||
* @notes
|
||||
* - size maximum packet size
|
||||
* - additional additional transaction opportunities per uframe */
|
||||
word_union_alone(wMaxPacketSize,
|
||||
uint16_t size :10;
|
||||
uint16_t additional : 2;
|
||||
uint16_t : 4;
|
||||
);
|
||||
|
||||
uint8_t bInterval; /* Interval for polling endpoint */
|
||||
} VPACKED_ALONE;
|
||||
|
||||
#include <vhex/usb/descriptor/types.h>
|
||||
#include <vhex/usb/utils.h>
|
||||
|
||||
/* USB_DECLARE_DESC_ENDPOINT - helper to declare endpoint descriptor */
|
||||
#define USB_DECLARE_DESC_ENDPOINT(name, ...) \
|
||||
struct usb_descriptor_endpoint name = \
|
||||
USB_DECLARE_DESC_ENDPOINT_RAW(__VA_ARGS__)
|
||||
|
||||
/* USB_DECLARE_DESC_ENDPOINT_RAW - helper to declare endpoint content */
|
||||
#define USB_DECLARE_DESC_ENDPOINT_RAW(...) \
|
||||
{ \
|
||||
.bLengh = sizeof(struct usb_descriptor_endpoint), \
|
||||
.bDescriptorType = USB_DESCRIPTOR_ENDPOINT, \
|
||||
__VA_ARGS__ \
|
||||
}
|
||||
|
||||
#endif /* __VHEX_USB_DESCRIPTOR_ENDPOINT_H__ */
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef __VHEX_USB_DESCRIPTOR_INTERFACE_H__
|
||||
#define __VHEX_USB_DESCRIPTOR_INTERFACE_H__ 1
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
|
||||
/* usb_descriptor_interface - USB Interface Descriptor struct */
|
||||
struct usb_descriptor_interface {
|
||||
uint8_t bLengh; /* size of this descriptor in bytes */
|
||||
uint8_t bDescriptorType; /* descriptor type (USB_DESCRIPTOR_DEVICE) */
|
||||
uint8_t bInterfaceNumber; /* the number of this interface */
|
||||
uint8_t bAlternateSetting; /* used to select an alternate settings */
|
||||
uint8_t bNumEndpoints; /* number of endpoint (except endpoint 0) */
|
||||
uint8_t bInterfaceClass; /* class code */
|
||||
uint8_t bInterfaceSubClass; /* subclass code */
|
||||
uint8_t bInterfaceProtocol; /* protocol code */
|
||||
uint8_t iInterface; /* index of string desc. for this interface */
|
||||
} VPACKED_ALONE;
|
||||
|
||||
#include <vhex/usb/descriptor/types.h>
|
||||
#include <vhex/usb/utils.h>
|
||||
|
||||
/* USB_DECLARE_DESC_INTERFACE - helper to declare interface descriptor */
|
||||
#define USB_DECLARE_DESC_INTERFACE(name, ...) \
|
||||
struct usb_descriptor_interface name = \
|
||||
USB_DECLARE_DESC_INTERFACE_RAW(__VA_ARGS__)
|
||||
|
||||
/* USB_DECLARE_DESC_INTERFACE_RAW - helper to declare interface content */
|
||||
#define USB_DECLARE_DESC_INTERFACE_RAW(...) \
|
||||
{ \
|
||||
.bLengh = sizeof(struct usb_descriptor_interface), \
|
||||
.bDescriptorType = USB_DESCRIPTOR_INTERFACE, \
|
||||
__VA_ARGS__ \
|
||||
}
|
||||
|
||||
#endif /* __VHEX_USB_DESCRIPTOR_DEVICE_H__ */
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef __VHEX_USB_DESCRIPTOR_TYPES_H__
|
||||
#define __VHEX_USB_DESCRIPTOR_TYPES_H__ 1
|
||||
|
||||
#define USB_DESCRIPTOR_DEVICE 1
|
||||
#define USB_DESCRIPTOR_CONFIGURATION 2
|
||||
#define USB_DESCRIPTOR_INTERFACE 4
|
||||
#define USB_DESCRIPTOR_ENDPOINT 7
|
||||
|
||||
#endif /* __VHEX_USB_DESCRIPTOR_TYPES_H__ */
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef __VHEX_USB_DEVICE_H__
|
||||
#define __VHEX_USB_DEVICE_H__ 1
|
||||
|
||||
#include <vhex/defs/types.h>
|
||||
#include <vhex/usb/descriptor/device.h>
|
||||
#include <vhex/usb/descriptor/configuration.h>
|
||||
#include <vhex/usb/descriptor/interface.h>
|
||||
#include <vhex/usb/descriptor/endpoint.h>
|
||||
|
||||
struct usb_full_interface {
|
||||
struct usb_descriptor_interface *descriptor;
|
||||
char **strs;
|
||||
struct usb_descriptor_endpoint **endpoint;
|
||||
};
|
||||
|
||||
struct usb_full_config {
|
||||
struct usb_descriptor_configuration *descriptor;
|
||||
char **strs;
|
||||
struct usb_full_interface **interface;
|
||||
};
|
||||
|
||||
struct usb_full_device {
|
||||
struct usb_descriptor_device *descriptor;
|
||||
char **strs;
|
||||
struct usb_full_config **config;
|
||||
};
|
||||
|
||||
#endif /* __VHEX_USB_DEVICE_H__ */
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef __VHEX_USB_UTILS_H__
|
||||
#define __VHEX_USB_UTILS_H__ 1
|
||||
|
||||
/* USB_WORD_TO() - convert word data to USB compatible one */
|
||||
#define USB_WORD_TO(data) ((((data) & 0xff00) >> 8) | (((data) & 0x00ff) << 8))
|
||||
|
||||
/* USB_REQ_DESCT_* - USB GET_DESCRIPTOR request type list */
|
||||
enum {
|
||||
USB_REQ_DESCT_DEVICE = 1,
|
||||
USB_REQ_DESCT_CONFIG = 2,
|
||||
USB_REQ_DESCT_STRING = 3,
|
||||
USB_REQ_DESCT_INTERFACE = 4,
|
||||
USB_REQ_DESCT_ENDPOINT = 5,
|
||||
USB_REQ_DESCT_DEVQUAL = 6,
|
||||
USB_REQ_DESCT_OSC = 7,
|
||||
USB_REQ_DESCT_POWER = 8,
|
||||
USB_REQ_DESCT_OTG = 9,
|
||||
};
|
||||
|
||||
#endif /* __VHEX_USB_UTILS_H__ */
|
|
@ -0,0 +1,150 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/usb.h>
|
||||
#include <vhex/driver/cpu.h>
|
||||
#include <vhex/usb.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//---
|
||||
// Internals
|
||||
//---
|
||||
|
||||
/* abitrary USB configuration limit (TODO : update me?) */
|
||||
#define __SH7305_USB_MAX_DC_CONF 2
|
||||
#define __SH7305_USB_MAX_DC_INTR 4
|
||||
#define __SH7305_USB_MAX_DC_ENDP 9
|
||||
|
||||
/* internal copy of each descriptor (TODO : update me?) */
|
||||
struct usb_descriptor_device __sh7305_usb_dc_device;
|
||||
struct usb_descriptor_configuration __sh7305_usb_dc_conf[__SH7305_USB_MAX_DC_CONF];
|
||||
struct usb_descriptor_interface __sh7305_usb_dc_interf[__SH7305_USB_MAX_DC_INTR];
|
||||
struct usb_descriptor_endpoint __sh7305_usb_dc_endpoint[__SH7305_USB_MAX_DC_ENDP];
|
||||
|
||||
/* sh7305_conf_check_conf() : check and patch interface desc. */
|
||||
static int sh7305_conf_check_endpoint(
|
||||
struct usb_descriptor_endpoint **endpoint,
|
||||
size_t *total
|
||||
) {
|
||||
int pipe_id;
|
||||
int i;
|
||||
|
||||
if (endpoint == NULL)
|
||||
return -3;
|
||||
for (i = 0 ; endpoint[i] != NULL ; ++i)
|
||||
{
|
||||
if (i >= __SH7305_USB_MAX_DC_ENDP) {
|
||||
usb_logger_write("- too many endpoint (%d)\n", i);
|
||||
return -4;
|
||||
}
|
||||
*total += sizeof(struct usb_descriptor_endpoint);
|
||||
pipe_id = sh7305_usb_pipe_find(endpoint[i]->bmAttributes.trans);
|
||||
if (pipe_id < 0)
|
||||
return pipe_id;
|
||||
endpoint[i]->bEndpointAddress.number = pipe_id;
|
||||
memcpy(
|
||||
&__sh7305_usb_dc_endpoint[i],
|
||||
endpoint[i],
|
||||
sizeof(struct usb_descriptor_endpoint)
|
||||
);
|
||||
usb_logger_write("- use pipe %d\n", pipe_id);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* sh7305_conf_check_conf() : check and patch interface desc. */
|
||||
static int sh7305_conf_check_interface(
|
||||
struct usb_full_interface **interface,
|
||||
size_t *total
|
||||
) {
|
||||
int nbendpoint;
|
||||
int i;
|
||||
|
||||
if (interface == NULL)
|
||||
return -3;
|
||||
for (i = 0 ; interface[i] != NULL ; ++i)
|
||||
{
|
||||
if (i >= __SH7305_USB_MAX_DC_INTR) {
|
||||
usb_logger_write("- too many interface (%d)\n", i);
|
||||
return -4;
|
||||
}
|
||||
//FIXME : check strings
|
||||
*total += sizeof(struct usb_descriptor_interface);
|
||||
nbendpoint = sh7305_conf_check_endpoint(interface[i]->endpoint, total);
|
||||
if (nbendpoint < 0)
|
||||
return nbendpoint;
|
||||
interface[i]->descriptor->bInterfaceNumber = i + 1;
|
||||
interface[i]->descriptor->bNumEndpoints = nbendpoint;
|
||||
memcpy(
|
||||
&__sh7305_usb_dc_interf[i],
|
||||
interface[i],
|
||||
sizeof(struct usb_descriptor_interface)
|
||||
);
|
||||
usb_logger_write("- use interface %d\n", i + 1);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* sh7305_conf_check_conf() : check and patch configuration desc. */
|
||||
static int sh7305_conf_check_conf(struct usb_full_config **config)
|
||||
{
|
||||
int nbinterf;
|
||||
size_t total;
|
||||
int i;
|
||||
|
||||
if (config == NULL)
|
||||
return -2;
|
||||
for (i = 0 ; config[i] != NULL ; ++i)
|
||||
{
|
||||
if (i >= __SH7305_USB_MAX_DC_CONF) {
|
||||
usb_logger_write("- too many configuration (%d)\n", i);
|
||||
return -4;
|
||||
}
|
||||
//FIXME : check strings
|
||||
total = sizeof(struct usb_descriptor_configuration);
|
||||
nbinterf = sh7305_conf_check_interface(config[i]->interface, &total);
|
||||
if (nbinterf < 0)
|
||||
return nbinterf;
|
||||
config[i]->descriptor->wTotalLengh = total;
|
||||
config[i]->descriptor->bNumInterfaces = nbinterf;
|
||||
config[i]->descriptor->bConfigurationValue = i + 1;
|
||||
memcpy(
|
||||
&__sh7305_usb_dc_conf[i],
|
||||
config[i],
|
||||
sizeof(struct usb_descriptor_configuration)
|
||||
);
|
||||
usb_logger_write("- use configuration %d\n", i + 1);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
//---
|
||||
// Public API
|
||||
//---
|
||||
|
||||
/* sh7305_usb_configuration_resolve() : check and resolve USB configuration */
|
||||
int sh7305_usb_configuration_resolve(struct usb_full_device *device)
|
||||
{
|
||||
int nbconf;
|
||||
|
||||
if (device == NULL)
|
||||
return -1;
|
||||
|
||||
//FIXME : check string validity
|
||||
|
||||
cpu_atomic_start();
|
||||
|
||||
/* patch configuration descriptors */
|
||||
nbconf = sh7305_conf_check_conf(device->config);
|
||||
if (nbconf < 0)
|
||||
return nbconf;
|
||||
|
||||
/* patch device descriptor */
|
||||
device->descriptor->bNumConfigurations = nbconf;
|
||||
memcpy(
|
||||
&__sh7305_usb_dc_device,
|
||||
device->descriptor,
|
||||
sizeof(struct usb_descriptor_device)
|
||||
);
|
||||
|
||||
cpu_atomic_end();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/usb.h>
|
||||
|
||||
/* sh7305_usb_dcp_write() : send data through DCP pipe */
|
||||
int sh7305_usb_dcp_write(void *buffer, size_t n)
|
||||
{
|
||||
//FIXME : common interface with other pipe
|
||||
//FIXME : check buffer size (block send)
|
||||
//
|
||||
/* force kevin */
|
||||
SH7305_USB_INTSTS0_CLEAR(VALID);
|
||||
|
||||
/* setup to write mode */
|
||||
SH7305_USB.CFIFOSEL.ISEL = 1;
|
||||
SH7305_USB.CFIFOSEL.CURPIPE = 0;
|
||||
SH7305_USB.CFIFOSEL.BIGEND = 1;
|
||||
SH7305_USB_REG_SYNC(SH7305_USB.CFIFOSEL.ISEL == 0);
|
||||
SH7305_USB_REG_SYNC(SH7305_USB.DCPCTR.BSTS == 0);
|
||||
|
||||
/* send data */
|
||||
SH7305_USB.DCPCTR.PID = 1;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
*((volatile uint8_t*)&SH7305_USB.CFIFO) = ((uint8_t*)buffer)[i];
|
||||
}
|
||||
|
||||
/* commit transfert */
|
||||
SH7305_USB.CFIFOCTR.BVAL = 1;
|
||||
SH7305_USB.DCPCTR.CCPL = 1;
|
||||
|
||||
usb_logger_write(
|
||||
"DCPCTR=%04X-CFIFOSEL=%04X-INTSTS=%04X\n"
|
||||
"buffer = %d\n",
|
||||
SH7305_USB.DCPCTR.word, SH7305_USB.CFIFOSEL.word, SH7305_USB.INTSTS0.word,
|
||||
n);
|
||||
|
||||
return n;
|
||||
}
|
|
@ -4,10 +4,48 @@
|
|||
|
||||
/* sh7305_usb_interrupt_handler() : interrupt handler invoked by hardware */
|
||||
void sh7305_usb_interrupt_handler(void)
|
||||
{
|
||||
dclear(C_WHITE);
|
||||
dtext(0, 0, C_BLACK, "USB INTERRUPT HANDLER !!!\n");
|
||||
dupdate();
|
||||
usb_logger_write("USB INTERRUPT HANDLER !!!!!\n");
|
||||
while (1) { __asm__ volatile ("nop"); }
|
||||
{ static char const * const device_st[] = {
|
||||
"powered", "default", "address", "configured",
|
||||
"suspended-powered", "suspended-default", "suspended-address",
|
||||
"suspended-configured",
|
||||
};
|
||||
/* Save PIPESEL to avoid concurrent access issues */
|
||||
uint16_t pipesel = SH7305_USB.PIPESEL.word;
|
||||
|
||||
if(SH7305_USB.INTSTS0.VBINT)
|
||||
{
|
||||
SH7305_USB_INTSTS0_CLEAR(VBINT);
|
||||
usb_logger_write("VBUS %s\n", SH7305_USB.INTSTS0.VBSTS ? "up" : "down");
|
||||
}
|
||||
else if(SH7305_USB.INTSTS0.CTRT)
|
||||
{
|
||||
SH7305_USB_INTSTS0_CLEAR(CTRT);
|
||||
if(SH7305_USB.INTSTS0.VALID)
|
||||
sh7305_usb_request_handle();
|
||||
}
|
||||
else if(SH7305_USB.INTSTS0.DVST)
|
||||
{
|
||||
SH7305_USB_INTSTS0_CLEAR(DVST);
|
||||
usb_logger_write("DVST %s", device_st[SH7305_USB.INTSTS0.DVSQ]);
|
||||
if(SH7305_USB.INTSTS0.DVSQ == SH7305_USB_DVSQ_ADDRESS) {
|
||||
usb_logger_write(": %04x\n", SH7305_USB.USBADDR.word);
|
||||
} else {
|
||||
usb_logger_write("\n");
|
||||
}
|
||||
|
||||
//TODO : handle config
|
||||
}
|
||||
else {
|
||||
dclear(C_WHITE);
|
||||
dprint(
|
||||
0, 0, C_BLACK,
|
||||
"USB INTERRUPT HANDLER (%02X) !!!\n",
|
||||
SH7305_USB.INTSTS0.word
|
||||
);
|
||||
dupdate();
|
||||
while (1) { __asm__ volatile ("nop"); }
|
||||
}
|
||||
|
||||
/* Restore PIPESEL which can have been used for transfers */
|
||||
SH7305_USB.PIPESEL.word = pipesel;
|
||||
}
|
||||
|
|
|
@ -7,10 +7,18 @@
|
|||
//---
|
||||
|
||||
/* sh7305_usb_open() : power on the module and setup USB module */
|
||||
int sh7305_usb_open(void *_, void *__)
|
||||
int sh7305_usb_open(struct usb_full_device *device)
|
||||
{
|
||||
int ret;
|
||||
|
||||
usb_logger_write("-- Open USB ---\n");
|
||||
|
||||
/* check and update device configuration */
|
||||
usb_logger_write("Configuration check...\n");
|
||||
ret = sh7305_usb_configuration_resolve(device);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* handle hardware power routine */
|
||||
if (sh7305_usb_hpowered() == false) {
|
||||
usb_logger_write("Poweron the hardware module...\n");
|
||||
|
@ -90,7 +98,7 @@ int sh7305_usb_open(void *_, void *__)
|
|||
* - VBSE =1 enable VBUS interruption
|
||||
* - RSME =0 disable Resume interruption
|
||||
* - SOFE =0 disable Frame Number Update interruption
|
||||
* - DVSE =0 disable Device State Transition
|
||||
* - DVSE =0 enable Device State Transition
|
||||
* - CTRE =0 disable Control Transfert Stage Transition
|
||||
* - BEMPE =0 disable Buffer Empty interrupt
|
||||
* - NRDYE =0 disable Buffer Not Ready interrupt
|
||||
|
@ -98,8 +106,8 @@ int sh7305_usb_open(void *_, void *__)
|
|||
SH7305_USB.INTENB0.VBSE = 1;
|
||||
SH7305_USB.INTENB0.RSME = 0;
|
||||
SH7305_USB.INTENB0.SOFE = 0;
|
||||
SH7305_USB.INTENB0.DVSE = 0;
|
||||
SH7305_USB.INTENB0.CTRE = 0;
|
||||
SH7305_USB.INTENB0.DVSE = 1;
|
||||
SH7305_USB.INTENB0.CTRE = 1;
|
||||
SH7305_USB.INTENB0.BEMPE = 0;
|
||||
SH7305_USB.INTENB0.NRDYE = 0;
|
||||
SH7305_USB.INTENB0.BEMPE = 0;
|
||||
|
@ -109,6 +117,14 @@ int sh7305_usb_open(void *_, void *__)
|
|||
SH7305_USB.NRDYENB.word = 0x0000;
|
||||
SH7305_USB.BEMPENB.word = 0x0000;
|
||||
|
||||
/* clear interrupt flags */
|
||||
SH7305_USB_INTSTS0_CLEAR(VBINT);
|
||||
SH7305_USB_INTSTS0_CLEAR(RESM);
|
||||
SH7305_USB_INTSTS0_CLEAR(SOFR);
|
||||
SH7305_USB_INTSTS0_CLEAR(DVST);
|
||||
SH7305_USB_INTSTS0_CLEAR(CTRT);
|
||||
SH7305_USB_INTSTS0_CLEAR(VALID);
|
||||
|
||||
/* install hardware interrupt handler and enable USB interruption */
|
||||
sh7305_intc_install_inth_generic(
|
||||
0xa20,
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/usb.h>
|
||||
#include <vhex/driver/cpu.h>
|
||||
|
||||
//---
|
||||
// Internals
|
||||
//---
|
||||
|
||||
/* internal pipe bitmap used for pipe status snapshot */
|
||||
static uint16_t pipe_bitmap = 0x0000;
|
||||
|
||||
/* sh7305_pipe_reserve() : try to reserve a pipe */
|
||||
static int sh7305_pipe_reserve(int pipe)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cpu_atomic_start();
|
||||
ret = -1;
|
||||
if ((pipe_bitmap & (0x0001 << pipe)) == 0x0000) {
|
||||
pipe_bitmap |= (0x0001 << pipe);
|
||||
ret = 0;
|
||||
}
|
||||
cpu_atomic_end();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//---
|
||||
// Public API
|
||||
//---
|
||||
|
||||
/* sh7305_usb_pipe_find() : try to find a pipe */
|
||||
int sh7305_usb_pipe_find(int type)
|
||||
{
|
||||
int min;
|
||||
int max;
|
||||
|
||||
max = -1;
|
||||
min = -1;
|
||||
|
||||
/* Isochronous transfert: use pipe 1,2 */
|
||||
if (type == 1) min=1, max=2;
|
||||
/* BULK transfer: use pipe 1..5 */
|
||||
if (type == 2) min=1, max=5;
|
||||
/* Interrupt transfer: use pipe 6..9 */
|
||||
if (type == 3) min=6, max=9;
|
||||
|
||||
/* Start from the end to avoir using Isochronous pipe for BULK */
|
||||
for (int pipe = max ; pipe >= min ; pipe--) {
|
||||
if (sh7305_pipe_reserve(pipe) == 0)
|
||||
return pipe;
|
||||
}
|
||||
|
||||
/* no pipe found, return error */
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
#include <vhex/driver/mpu/sh/sh7305/usb.h>
|
||||
#include <vhex/usb/utils.h>
|
||||
#include <vhex/display.h>
|
||||
#include <vhex/usb.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
//---
|
||||
// Internal error API
|
||||
//---
|
||||
|
||||
/* defined in <configuration.c> */
|
||||
extern struct usb_descriptor_device __sh7305_usb_dc_device;
|
||||
extern struct usb_descriptor_configuration *__sh7305_usb_dc_conf;
|
||||
extern struct usb_descriptor_interface *__sh7305_usb_dc_interf;
|
||||
extern struct usb_descriptor_endpoint *__sh7305_usb_dc_endpoint;
|
||||
|
||||
/* sh7305_usb_request_unimplemented() : not implemented request */
|
||||
static void sh7305_usb_request_unimplemented(
|
||||
char const * const name,
|
||||
int wValue,
|
||||
int wIndex,
|
||||
int wLength
|
||||
) {
|
||||
dclear(C_WHITE);
|
||||
dprint(0, 0, C_BLACK, "%s (%d, %d, %d)", name, wValue, wIndex, wLength);
|
||||
dupdate();
|
||||
while (1) { __asm__ volatile ("sleep"); }
|
||||
}
|
||||
|
||||
/* sh7305_usb_request_error() : USB request error */
|
||||
static void sh7305_usb_request_error(char const * const text, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, text);
|
||||
|
||||
dclear(C_WHITE);
|
||||
dvprint(0, 0, C_BLACK, text, ap);
|
||||
dupdate();
|
||||
while (1) { __asm__ volatile ("sleep"); }
|
||||
}
|
||||
|
||||
/* sh7305_usb_request_get_descriptor() : send descriptor through DCP */
|
||||
static void sh7305_usb_request_get_descriptor(int wValue, int wIndex, int wLength)
|
||||
{
|
||||
int type;
|
||||
int indx;
|
||||
|
||||
(void)wIndex;
|
||||
(void)wLength;
|
||||
|
||||
/* fetch descriptor request */
|
||||
type = (wValue & 0xff00) >> 8;
|
||||
indx = (wValue & 0x00ff) >> 0;
|
||||
|
||||
/* handle request description type */
|
||||
if (type == USB_REQ_DESCT_DEVICE) {
|
||||
usb_logger_write("DCP write DEVICE_DESC\n");
|
||||
sh7305_usb_dcp_write(
|
||||
&__sh7305_usb_dc_device,
|
||||
sizeof(struct usb_descriptor_device)
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (type == USB_REQ_DESCT_CONFIG) {
|
||||
sh7305_usb_request_unimplemented("GET_DESC_CONF", indx, 0, 0);
|
||||
return;
|
||||
}
|
||||
if (type == USB_REQ_DESCT_STRING) {
|
||||
sh7305_usb_request_unimplemented("GET_DESC_STR", indx, 0, 0);
|
||||
return;
|
||||
}
|
||||
if (type == USB_REQ_DESCT_INTERFACE) {
|
||||
sh7305_usb_request_unimplemented("GET_DESC_INTERFACE", indx, 0, 0);
|
||||
return;
|
||||
}
|
||||
if (type == USB_REQ_DESCT_ENDPOINT) {
|
||||
sh7305_usb_request_unimplemented("GET_DESC_ENDPOINT", indx, 0, 0);
|
||||
return;
|
||||
}
|
||||
if (type == USB_REQ_DESCT_DEVQUAL) {
|
||||
sh7305_usb_request_unimplemented("GET_DESC_DEVQUAL", indx, 0, 0);
|
||||
return;
|
||||
}
|
||||
if (type == USB_REQ_DESCT_OSC) {
|
||||
sh7305_usb_request_unimplemented("GET_DESC_OSC", indx, 0, 0);
|
||||
return;
|
||||
}
|
||||
if (type == USB_REQ_DESCT_POWER) {
|
||||
sh7305_usb_request_unimplemented("GET_DESC_POWER", indx, 0, 0);
|
||||
return;
|
||||
}
|
||||
if (type == USB_REQ_DESCT_OTG) {
|
||||
sh7305_usb_request_unimplemented("GET_DESC_OTG", indx, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* handle USB error */
|
||||
sh7305_usb_request_error(
|
||||
"GET_DESCRIPTOR : unable to resolve type %d (%04X)",
|
||||
type, wValue
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
//---
|
||||
// Public API
|
||||
//---
|
||||
|
||||
/* sh7305_usb_request_handle() : handle USB request */
|
||||
void sh7305_usb_request_handle(void)
|
||||
{
|
||||
int bmRequestType;
|
||||
int bRequest;
|
||||
int wValue;
|
||||
int wIndex;
|
||||
int wLength;
|
||||
|
||||
/* fetch request information */
|
||||
bmRequestType = SH7305_USB.USBREQ.BMREQUEST;
|
||||
bRequest = SH7305_USB.USBREQ.BREQUEST;
|
||||
wValue = SH7305_USB.USBVAL.word;
|
||||
wIndex = SH7305_USB.USBINDX.word;
|
||||
wLength = SH7305_USB.USBLENG.word;
|
||||
|
||||
/* clear VALID bits */
|
||||
SH7305_USB_INTSTS0_CLEAR(VALID);
|
||||
|
||||
/* check GET request */
|
||||
if (bmRequestType == 0x80) {
|
||||
if (bRequest == SH7305_USB_REQT_GET_STATUS) {
|
||||
sh7305_usb_request_unimplemented("GET_STATUS", wValue, wIndex, wLength);
|
||||
return;
|
||||
}
|
||||
if (bRequest == SH7305_USB_REQT_GET_DESCRIPTOR) {
|
||||
sh7305_usb_request_get_descriptor(wValue, wIndex, wLength);
|
||||
return;
|
||||
}
|
||||
if (bRequest == SH7305_USB_REQT_GET_CONFIGURATION) {
|
||||
sh7305_usb_request_unimplemented(
|
||||
"GET_CONFIGURATION", wValue, wIndex, wLength
|
||||
);
|
||||
return;
|
||||
}
|
||||
usb_logger_write("request: unable to resolve bRequest %d\n", bRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
/* check SET request */
|
||||
if (bmRequestType == 0x00) {
|
||||
if (bRequest == SH7305_USB_REQT_CLEAR_FEATURE) {
|
||||
sh7305_usb_request_unimplemented(
|
||||
"CLEAR_FEATURE", wValue, wIndex, wLength
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (bRequest == SH7305_USB_REQT_SET_FEATURE) {
|
||||
sh7305_usb_request_unimplemented(
|
||||
"SET_FEATURE", wValue, wIndex, wLength
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (bRequest == SH7305_USB_REQT_SET_ADDRESS) {
|
||||
sh7305_usb_request_unimplemented(
|
||||
"SET_ADDRESS", wValue, wIndex, wLength
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (bRequest == SH7305_USB_REQT_SET_DESCRIPTOR) {
|
||||
sh7305_usb_request_unimplemented(
|
||||
"SET_DESCRIPTOR", wValue, wIndex, wLength
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (bRequest == SH7305_USB_REQT_SET_CONFIGURATION) {
|
||||
sh7305_usb_request_unimplemented(
|
||||
"SET_CONFIGURATION", wValue, wIndex, wLength
|
||||
);
|
||||
return;
|
||||
}
|
||||
usb_logger_write("request: unable to resolve bRequest %d\n", bRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
/* non-standar error */
|
||||
sh7305_usb_request_error(
|
||||
"request: unable to resolve bnRequestType %d\n", bmRequestType
|
||||
);
|
||||
}
|
|
@ -8,17 +8,42 @@
|
|||
// User-level API
|
||||
//---
|
||||
|
||||
/* dvprint() : display formated text (vargs version) */
|
||||
did_t dvprint(int x, int y, int fg, char const * const text, va_list ap)
|
||||
{
|
||||
char buff[1024];
|
||||
|
||||
vsnprintf(buff, 1024, text, ap);
|
||||
|
||||
return (dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT | DTEXT_TOP, buff, -1));
|
||||
}
|
||||
|
||||
/* dprint() : display formated string */
|
||||
did_t dprint(int x, int y, int fg, char const * const text, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buff[1024];
|
||||
did_t did;
|
||||
|
||||
va_start(ap, text);
|
||||
vsnprintf(buff, 1024, text, ap);
|
||||
did = dvprint(x, y, fg, text, ap);
|
||||
va_end(ap);
|
||||
|
||||
return (dtext_opt(x, y, fg, C_NONE, DTEXT_LEFT | DTEXT_TOP, buff, -1));
|
||||
return did;
|
||||
}
|
||||
|
||||
/* dvprint_opt(): Display a string of text */
|
||||
did_t dvprint_opt(
|
||||
int x, int y,
|
||||
int fg, int bg,
|
||||
int align,
|
||||
char const *text,
|
||||
va_list ap
|
||||
) {
|
||||
char buff[1024];
|
||||
|
||||
vsnprintf(buff, 1024, text, ap);
|
||||
|
||||
return (dtext_opt(x, y, fg, bg, align, buff, -1));
|
||||
}
|
||||
|
||||
/* dprint_opt(): Display a string of text */
|
||||
|
@ -29,11 +54,11 @@ did_t dprint_opt(
|
|||
char const *text, ...
|
||||
) {
|
||||
va_list ap;
|
||||
char buff[1024];
|
||||
did_t did;
|
||||
|
||||
va_start(ap, text);
|
||||
vsnprintf(buff, 1024, text, ap);
|
||||
did = dvprint_opt(x, y, fg, bg, align, text, ap);
|
||||
va_end(ap);
|
||||
|
||||
return (dtext_opt(x, y, fg, bg, align, buff, -1));
|
||||
return did;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue