main: more work on fixing stuff
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
1c38c58a6f
commit
ffd0285613
@ -5,8 +5,20 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct usb_device;
|
||||
struct usb_setup_request;
|
||||
|
||||
void usb_isr(void);
|
||||
void usb_init(void);
|
||||
void usb_connect(void);
|
||||
|
||||
void usb_poll(void);
|
||||
int usb_irq_happened(void);
|
||||
void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup);
|
||||
int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count);
|
||||
int usb_ack(struct usb_device *dev, int epnum);
|
||||
int usb_err(struct usb_device *dev, int epnum);
|
||||
int usb_recv(struct usb_device *dev, void *buffer, unsigned int buffer_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -1,243 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Grainuum Software USB Stack *
|
||||
* *
|
||||
* MIT License: *
|
||||
* Copyright (c) 2016 Sean Cross *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a *
|
||||
* copy of this software and associated documentation files (the *
|
||||
* "Software"), to deal in the Software without restriction, including *
|
||||
* without limitation the rights to use, copy, modify, merge, publish, *
|
||||
* distribute, distribute with modifications, sublicense, and/or sell *
|
||||
* copies of the Software, and to permit persons to whom the Software is *
|
||||
* furnished to do so, subject to the following conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included *
|
||||
* in all copies or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
|
||||
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
|
||||
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
* *
|
||||
* Except as contained in this notice, the name(s) of the above copyright *
|
||||
* holders shall not be used in advertising or otherwise to promote the *
|
||||
* sale, use or other dealings in this Software without prior written *
|
||||
* authorization. *
|
||||
****************************************************************************/
|
||||
|
||||
#include <generated/csr.h>
|
||||
#include <grainuum.h>
|
||||
#include <printf.h>
|
||||
|
||||
__attribute__((weak)) void grainuumConnectPre(struct GrainuumUSB *usb)
|
||||
{
|
||||
(void)usb;
|
||||
}
|
||||
__attribute__((weak)) void grainuumConnectPost(struct GrainuumUSB *usb)
|
||||
{
|
||||
(void)usb;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void grainuumDisconnectPre(struct GrainuumUSB *usb)
|
||||
{
|
||||
(void)usb;
|
||||
}
|
||||
__attribute__((weak)) void grainuumDisconnectPost(struct GrainuumUSB *usb)
|
||||
{
|
||||
(void)usb;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void grainuumReceivePacket(struct GrainuumUSB *usb)
|
||||
{
|
||||
(void)usb;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void grainuumInitPre(struct GrainuumUSB *usb)
|
||||
{
|
||||
(void)usb;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void grainuumInitPost(struct GrainuumUSB *usb)
|
||||
{
|
||||
(void)usb;
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
void grainuum_receive_packet(struct GrainuumUSB *usb)
|
||||
{
|
||||
grainuumReceivePacket(usb);
|
||||
}
|
||||
|
||||
int grainuumCaptureI(struct GrainuumUSB *usb, uint8_t samples[67])
|
||||
{
|
||||
#if 0
|
||||
int ret;
|
||||
const uint8_t nak_pkt[] = {USB_PID_NAK};
|
||||
const uint8_t ack_pkt[] = {USB_PID_ACK};
|
||||
|
||||
ret = usbPhyReadI(usb, samples);
|
||||
if (ret <= 0) {
|
||||
if (ret != -1)
|
||||
usbPhyWriteI(usb, nak_pkt, sizeof(nak_pkt));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the byte counter for later inspection */
|
||||
samples[11] = ret;
|
||||
|
||||
switch (samples[0]) {
|
||||
case USB_PID_IN:
|
||||
/* Make sure we have queued data, and that it's for this particular EP */
|
||||
if ((!usb->queued_size)
|
||||
|| (((((const uint16_t *)(samples+1))[0] >> 7) & 0xf) != usb->queued_epnum))
|
||||
{
|
||||
usbPhyWriteI(usb, nak_pkt, sizeof(nak_pkt));
|
||||
break;
|
||||
}
|
||||
|
||||
usbPhyWriteI(usb, usb->queued_data, usb->queued_size);
|
||||
break;
|
||||
|
||||
case USB_PID_SETUP:
|
||||
grainuum_receive_packet(usb);
|
||||
break;
|
||||
|
||||
case USB_PID_OUT:
|
||||
grainuum_receive_packet(usb);
|
||||
break;
|
||||
|
||||
case USB_PID_ACK:
|
||||
/* Allow the next byte to be sent */
|
||||
usb->queued_size = 0;
|
||||
grainuum_receive_packet(usb);
|
||||
break;
|
||||
|
||||
case USB_PID_DATA0:
|
||||
case USB_PID_DATA1:
|
||||
usbPhyWriteI(usb, ack_pkt, sizeof(ack_pkt));
|
||||
grainuum_receive_packet(usb);
|
||||
break;
|
||||
|
||||
default:
|
||||
usbPhyWriteI(usb, nak_pkt, sizeof(nak_pkt));
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
uint8_t obufbuf[128];
|
||||
uint32_t obufbuf_cnt = 0;
|
||||
while (!usb_ep_0_out_obuf_empty_read())
|
||||
{
|
||||
uint32_t obh = usb_ep_0_out_obuf_head_read();
|
||||
obufbuf[obufbuf_cnt++] = obh;
|
||||
usb_ep_0_out_obuf_head_write(1);
|
||||
}
|
||||
|
||||
int i;
|
||||
static int loops;
|
||||
uint8_t last_tok = usb_ep_0_out_last_tok_read();
|
||||
printf("i: %d b: %d olt: %02x --", loops, obufbuf_cnt, last_tok); //obe: %d obh: %02x\n", i, obe, obh);
|
||||
for (i = 0; i < obufbuf_cnt; i++)
|
||||
{
|
||||
printf(" %02x", obufbuf[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
usb_ep_0_out_ev_pending_write((1 << 1));
|
||||
|
||||
// Response
|
||||
if (!usb_ep_0_in_ibuf_empty_read())
|
||||
{
|
||||
printf("USB ibuf still has data\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t usb_in_pending = usb_ep_0_out_ev_pending_read();
|
||||
if (usb_in_pending)
|
||||
{
|
||||
printf("USB EP0 in pending is: %02x\n", usb_in_pending);
|
||||
return 0;
|
||||
}
|
||||
|
||||
grainuumProcess(usb, last_tok, obufbuf, obufbuf_cnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int grainuumInitialized(struct GrainuumUSB *usb)
|
||||
{
|
||||
if (!usb)
|
||||
return 0;
|
||||
|
||||
return usb->initialized;
|
||||
}
|
||||
|
||||
enum usb_responses {
|
||||
USB_STALL = 0b11,
|
||||
USB_ACK = 0b00,
|
||||
USB_NAK = 0b01,
|
||||
USB_NONE = 0b10,
|
||||
};
|
||||
|
||||
void grainuumWriteQueue(struct GrainuumUSB *usb, int epnum,
|
||||
const void *buffer, int size)
|
||||
{
|
||||
usb->queued_data = buffer;
|
||||
usb->queued_epnum = epnum;
|
||||
usb->queued_size = size;
|
||||
|
||||
int i;
|
||||
const uint8_t *buffer_u8 = buffer;
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
usb_ep_0_in_ibuf_head_write(buffer_u8[i]);
|
||||
}
|
||||
// Indicate that we respond with an ACK
|
||||
usb_ep_0_in_respond_write(USB_ACK);
|
||||
usb_ep_0_in_ev_pending_write(0xff);
|
||||
}
|
||||
|
||||
void grainuumInit(struct GrainuumUSB *usb,
|
||||
struct GrainuumConfig *cfg)
|
||||
{
|
||||
|
||||
if (usb->initialized)
|
||||
return;
|
||||
|
||||
printf("Initializing USB to %08x, cfg to 0x%08x 0x%08x\n", usb, cfg, cfg->getDescriptor);
|
||||
grainuumInitPre(usb);
|
||||
|
||||
usb->cfg = cfg;
|
||||
usb->state.usb = usb;
|
||||
cfg->usb = usb;
|
||||
|
||||
usb->initialized = 1;
|
||||
|
||||
grainuumInitPost(usb);
|
||||
}
|
||||
|
||||
void grainuumDisconnect(struct GrainuumUSB *usb)
|
||||
{
|
||||
|
||||
grainuumDisconnectPre(usb);
|
||||
|
||||
usb_pullup_out_write(0);
|
||||
|
||||
grainuumDisconnectPost(usb);
|
||||
}
|
||||
|
||||
void grainuumConnect(struct GrainuumUSB *usb)
|
||||
{
|
||||
|
||||
grainuumConnectPre(usb);
|
||||
|
||||
usb_pullup_out_write(1);
|
||||
|
||||
grainuumConnectPost(usb);
|
||||
}
|
@ -1,348 +0,0 @@
|
||||
/****************************************************************************
|
||||
* Grainuum Software USB Stack *
|
||||
* *
|
||||
* MIT License: *
|
||||
* Copyright (c) 2016 Sean Cross *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a *
|
||||
* copy of this software and associated documentation files (the *
|
||||
* "Software"), to deal in the Software without restriction, including *
|
||||
* without limitation the rights to use, copy, modify, merge, publish, *
|
||||
* distribute, distribute with modifications, sublicense, and/or sell *
|
||||
* copies of the Software, and to permit persons to whom the Software is *
|
||||
* furnished to do so, subject to the following conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included *
|
||||
* in all copies or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
|
||||
* IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
|
||||
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
|
||||
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
|
||||
* THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
* *
|
||||
* Except as contained in this notice, the name(s) of the above copyright *
|
||||
* holders shall not be used in advertising or otherwise to promote the *
|
||||
* sale, use or other dealings in this Software without prior written *
|
||||
* authorization. *
|
||||
****************************************************************************/
|
||||
#include "grainuum.h"
|
||||
#include <printf.h>
|
||||
#include <generated/csr.h>
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
|
||||
void *memcpy(void *dest, const void *src, unsigned int n);
|
||||
|
||||
enum usb_state_packet_type {
|
||||
packet_type_none,
|
||||
packet_type_setup,
|
||||
packet_type_setup_in,
|
||||
packet_type_setup_out,
|
||||
packet_type_in,
|
||||
packet_type_out,
|
||||
};
|
||||
|
||||
__attribute__((weak))
|
||||
void grainuumSendWait(struct GrainuumUSB *usb, int epnum,
|
||||
const void *data, int size)
|
||||
{
|
||||
(void)usb;
|
||||
(void)epnum;
|
||||
(void)data;
|
||||
(void)size;
|
||||
}
|
||||
|
||||
static uint16_t crc16_add(uint16_t crc, uint8_t c, uint16_t poly)
|
||||
{
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if ((crc ^ c) & 1)
|
||||
crc = (crc >> 1) ^ poly;
|
||||
else
|
||||
crc >>= 1;
|
||||
c >>= 1;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
static uint16_t crc16(const uint8_t *data, uint32_t size,
|
||||
uint16_t init, uint32_t poly)
|
||||
{
|
||||
|
||||
while (size--)
|
||||
init = crc16_add(init, *data++, poly);
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
static void grainuum_state_clear_tx(struct GrainuumState *state, int result)
|
||||
{
|
||||
struct GrainuumUSB *usb = state->usb;
|
||||
|
||||
/* If a thread is blocking, wake it up with a failure */
|
||||
if (usb->cfg->sendDataFinished && state->packet_queued)
|
||||
usb->cfg->sendDataFinished(usb, result);
|
||||
state->data_out_left = 0;
|
||||
state->data_out_max = 0;
|
||||
state->data_out = NULL;
|
||||
state->packet_queued = 0;
|
||||
}
|
||||
|
||||
static void grainuum_state_process_tx(struct GrainuumState *state)
|
||||
{
|
||||
|
||||
uint16_t crc;
|
||||
struct GrainuumUSB *usb = state->usb;
|
||||
|
||||
/* Don't allow us to re-prepare data */
|
||||
if (state->packet_queued) {
|
||||
return;
|
||||
}
|
||||
state->packet_queued = 1;
|
||||
|
||||
/* If there's no data to send, then don't send any */
|
||||
if (!state->data_out) {
|
||||
state->packet_queued = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we've sent all of our data, then there's nothing else to send */
|
||||
if ((state->data_out_left < 0) || (state->data_out_max < 0)) {
|
||||
grainuum_state_clear_tx(state, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pick the correct PID, DATA0 or DATA1 */
|
||||
// if (state->data_buffer & (1 << state->tok_epnum))
|
||||
// state->packet.pid = USB_PID_DATA1;
|
||||
// else
|
||||
// state->packet.pid = USB_PID_DATA0;
|
||||
|
||||
/* If there's no data, prepare a special NULL packet */
|
||||
if ((state->data_out_left == 0) || (state->data_out_max == 0)) {
|
||||
|
||||
/* The special-null thing only happens for EP0 */
|
||||
if (state->data_out_epnum != 0) {
|
||||
grainuum_state_clear_tx(state, 0);
|
||||
return;
|
||||
}
|
||||
state->packet.data[0] = 0; /* CRC16 for empty packets is 0 */
|
||||
state->packet.data[1] = 0;
|
||||
state->packet.size = 2;
|
||||
grainuumWriteQueue(usb, state->data_out_epnum,
|
||||
&state->packet, state->packet.size + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Keep the packet size to 8 bytes max */
|
||||
if (state->data_out_left > GRAINUUM_PACKET_SIZE_MAX)
|
||||
state->packet.size = GRAINUUM_PACKET_SIZE_MAX;
|
||||
else
|
||||
state->packet.size = state->data_out_left;
|
||||
|
||||
/* Limit the amount of data transferred to data_out_max */
|
||||
if (state->packet.size > state->data_out_max)
|
||||
state->packet.size = state->data_out_max;
|
||||
|
||||
/* Copy over data bytes */
|
||||
memcpy(state->packet.data, state->data_out, state->packet.size);
|
||||
|
||||
/* Calculate and copy the crc16 */
|
||||
crc = ~crc16(state->packet.data, state->packet.size, 0xffff, 0xa001);
|
||||
state->packet.data[state->packet.size++] = crc;
|
||||
state->packet.data[state->packet.size++] = crc >> 8;
|
||||
|
||||
/* Prepare the packet, including the PID at the end */
|
||||
grainuumWriteQueue(usb, state->data_out_epnum,
|
||||
&state->packet, state->packet.size + 1);
|
||||
}
|
||||
|
||||
/* Called when a packet is ACKed.
|
||||
* Updates the outgoing packet buffer.
|
||||
*/
|
||||
static void usbStateTransferSuccess(struct GrainuumState *state)
|
||||
{
|
||||
|
||||
/* Reduce the amount of data left.
|
||||
* If the packet is divisible by 8, this will cause one more call
|
||||
* to this function with state->data_out_left == 0. This will send
|
||||
* a NULL packet, which indicates end-of-transfer.
|
||||
*/
|
||||
state->data_out_left -= GRAINUUM_PACKET_SIZE_MAX;
|
||||
state->data_out_max -= GRAINUUM_PACKET_SIZE_MAX;
|
||||
state->data_out += GRAINUUM_PACKET_SIZE_MAX;
|
||||
|
||||
if ((state->data_out_left < 0) || (state->data_out_max < 0)) {
|
||||
grainuum_state_clear_tx(state, 0);
|
||||
|
||||
/* End of a State setup packet */
|
||||
if (state->packet_type == packet_type_setup_out)
|
||||
state->packet_type = packet_type_none;
|
||||
if (state->packet_type == packet_type_setup_in)
|
||||
state->packet_type = packet_type_none;
|
||||
if (state->packet_type == packet_type_out)
|
||||
state->packet_type = packet_type_none;
|
||||
}
|
||||
|
||||
state->packet_queued = 0;
|
||||
}
|
||||
|
||||
/* Send data down the wire, interrupting any existing
|
||||
* data that may be queued.
|
||||
*/
|
||||
static int grainuum_state_send_data(struct GrainuumState *state,
|
||||
int epnum,
|
||||
const void *data,
|
||||
int size,
|
||||
int max)
|
||||
{
|
||||
|
||||
/* De-queue any data that may already be queued. */
|
||||
grainuum_state_clear_tx(state, 1);
|
||||
|
||||
state->data_out_epnum = epnum;
|
||||
state->data_out_left = size;
|
||||
state->data_out_max = max;
|
||||
state->data_out = data;
|
||||
|
||||
grainuum_state_process_tx(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void grainuumDropData(struct GrainuumUSB *usb)
|
||||
{
|
||||
usb->state.packet_queued = 0;
|
||||
usb->state.data_out = 0;
|
||||
grainuumWriteQueue(usb, 0, NULL, 0);
|
||||
}
|
||||
|
||||
int grainuumDataQueued(struct GrainuumUSB *usb)
|
||||
{
|
||||
return (usb->state.data_out || usb->state.packet_queued);
|
||||
}
|
||||
|
||||
int grainuumSendData(struct GrainuumUSB *usb, int epnum,
|
||||
const void *data, int size)
|
||||
{
|
||||
|
||||
struct GrainuumState *state = &usb->state;
|
||||
int ret;
|
||||
|
||||
if (state->data_out || !state->address || state->packet_queued) {
|
||||
return -11; /* EAGAIN */
|
||||
}
|
||||
|
||||
ret = grainuum_state_send_data(state, epnum, data, size, size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
grainuum_state_process_tx(state);
|
||||
|
||||
if (usb->cfg->sendDataStarted)
|
||||
usb->cfg->sendDataStarted(usb, epnum, data, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int grainuum_state_process_setup(struct GrainuumState *state, const uint8_t packet[10])
|
||||
{
|
||||
|
||||
const struct usb_setup_packet *setup;
|
||||
const void *response = (void *)-1;
|
||||
uint32_t response_len = 0;
|
||||
struct GrainuumUSB *usb = state->usb;
|
||||
struct GrainuumConfig *cfg = usb->cfg;
|
||||
|
||||
setup = (const struct usb_setup_packet *)packet;
|
||||
|
||||
if ((setup->bmRequestType == 0x00) && (setup->bRequest == SET_ADDRESS)) {
|
||||
state->address = setup->wValue;
|
||||
}
|
||||
else if ((setup->bmRequestType == 0x00) && (setup->bRequest == SET_CONFIGURATION)) {
|
||||
if (cfg->setConfigNum)
|
||||
cfg->setConfigNum(usb, setup->wValue);
|
||||
}
|
||||
else {
|
||||
printf("Going to get descriptor @ 0x%08x\n", cfg->getDescriptor);
|
||||
response_len = cfg->getDescriptor(usb, setup, &response);
|
||||
}
|
||||
grainuum_state_send_data(state, state->tok_epnum, response, response_len, setup->wLength);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void grainuum_state_parse_data(struct GrainuumState *state,
|
||||
const uint8_t packet[GRAINUUM_PACKET_SIZE_MAX + 2],
|
||||
uint32_t size)
|
||||
{
|
||||
(void)size;
|
||||
struct GrainuumUSB *usb = state->usb;
|
||||
|
||||
switch (state->packet_type) {
|
||||
|
||||
case packet_type_setup:
|
||||
grainuum_state_process_setup(state, packet);
|
||||
grainuum_state_process_tx(state);
|
||||
state->packet_type = packet_type_none;
|
||||
break;
|
||||
|
||||
case packet_type_out:
|
||||
// XXX HACK: An OUT packet gets generated (on Windows at least) when
|
||||
// terminating a SETUP sequence. This seems odd.
|
||||
if (state->tok_epnum == 0)
|
||||
break;
|
||||
// Copy over the packet, minus the CRC16
|
||||
memcpy(state->tok_buf + state->tok_pos, packet, size - 2);
|
||||
state->tok_pos += (size - 2);
|
||||
if (!usb->cfg->receiveData(usb, state->tok_epnum, size - 2, packet))
|
||||
state->packet_type = packet_type_none;
|
||||
break;
|
||||
|
||||
case packet_type_in:
|
||||
case packet_type_none:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void grainuumProcess(struct GrainuumUSB *usb,
|
||||
uint8_t pid,
|
||||
const uint8_t packet[GRAINUUM_PACKET_SIZE_MAX + 3],
|
||||
uint32_t size)
|
||||
{
|
||||
|
||||
// uint32_t size = packet[GRAINUUM_PACKET_SIZE_MAX + 3];
|
||||
struct GrainuumState *state = &usb->state;
|
||||
printf("Processing %d byte packet %x %08x (%02x)\n", size, pid, packet, packet[0]);
|
||||
switch(pid) {
|
||||
case VUSB_PID_SETUP:
|
||||
printf("Setup packet!\n");
|
||||
state->packet_type = packet_type_setup;
|
||||
grainuum_state_clear_tx(state, 1);
|
||||
break;
|
||||
|
||||
case USB_PID_OUT:
|
||||
state->packet_type = packet_type_out;
|
||||
state->tok_pos = 0;
|
||||
state->tok_buf = usb->cfg->getReceiveBuffer(usb, state->tok_epnum, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unrecognized PID: %02x\n", pid);
|
||||
break;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
usb_ep_0_in_respond_write(0);
|
||||
usb_ep_0_in_ev_pending_write(0xff);
|
||||
}
|
||||
|
||||
//state->data_buffer |= (1 << state->tok_epnum);
|
||||
grainuum_state_parse_data(state, packet, size);
|
||||
}
|
@ -67,13 +67,12 @@ int main(int argc, char **argv)
|
||||
printf("\n\nUSB API: %s\n", usb_hw_api());
|
||||
// printf("Press any key to enable USB...\n");
|
||||
|
||||
usb_print_status();
|
||||
// usb_print_status();
|
||||
// uart_read();
|
||||
printf("Enabling USB\n");
|
||||
usb_connect();
|
||||
printf("USB enabled, waiting for packet...\n");
|
||||
// usb_wait();
|
||||
usb_print_status();
|
||||
// usb_print_status();
|
||||
int last = 0;
|
||||
while (1)
|
||||
{
|
||||
@ -81,8 +80,7 @@ int main(int argc, char **argv)
|
||||
last = usb_irq_happened();
|
||||
printf("USB %d IRQ happened\n", last);
|
||||
}
|
||||
// printf("x");
|
||||
usb_print_status();
|
||||
usb_poll();
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -8,101 +8,22 @@
|
||||
|
||||
#ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR
|
||||
|
||||
/* The state machine states of a control pipe */
|
||||
enum CONTROL_STATE
|
||||
{
|
||||
WAIT_SETUP,
|
||||
IN_DATA,
|
||||
OUT_DATA,
|
||||
LAST_IN_DATA,
|
||||
WAIT_STATUS_IN,
|
||||
WAIT_STATUS_OUT,
|
||||
STALLED,
|
||||
} control_state;
|
||||
|
||||
#define NUM_BUFFERS 4
|
||||
#define BUFFER_SIZE 64
|
||||
#define EP_INTERVAL_MS 6
|
||||
|
||||
//static struct GrainuumUSB usb;
|
||||
//static uint8_t usb_buf[67];
|
||||
static const uint8_t hid_report_descriptor[] = {
|
||||
0x06, 0x00, 0xFF, // (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined
|
||||
0x09, 0x00, // (LOCAL) USAGE 0xFF000000
|
||||
0xA1, 0x01, // (MAIN) COLLECTION 0x01 Application (Usage=0xFF000000: Page=Vendor-defined, Usage=, Type=)
|
||||
0x26, 0xFF, 0x00, // (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255)
|
||||
0x75, 0x08, // (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field
|
||||
0x95, 0x08, // (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields
|
||||
0x06, 0xFF, 0xFF, // (GLOBAL) USAGE_PAGE 0xFFFF Vendor-defined
|
||||
0x09, 0x01, // (LOCAL) USAGE 0xFFFF0001
|
||||
0x81, 0x02, // (MAIN) INPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
|
||||
0x09, 0x01, // (LOCAL) USAGE 0xFFFF0001
|
||||
0x91, 0x02, // (MAIN) OUTPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap
|
||||
0xC0, // (MAIN) END_COLLECTION Application
|
||||
};
|
||||
|
||||
static const struct usb_device_descriptor device_descriptor = {
|
||||
.bLength = 18, //sizeof(struct usb_device_descriptor),
|
||||
.bDescriptorType = DT_DEVICE, /* DEVICE */
|
||||
.bcdUSB = 0x0200, /* USB 2.0 */
|
||||
.bDeviceClass = 0x00,
|
||||
.bDeviceSubClass = 0x00,
|
||||
.bDeviceProtocol = 0x00,
|
||||
.bMaxPacketSize0 = 0x08, /* 8-byte packets max */
|
||||
.idVendor = 0x1209,
|
||||
.idProduct = 0x9317,
|
||||
.bcdDevice = 0x0114, /* Device release 1.14 */
|
||||
.iManufacturer = 0x02, /* No manufacturer string */
|
||||
.iProduct = 0x01, /* Product name in string #2 */
|
||||
.iSerialNumber = 0x03, /* No serial number */
|
||||
.bNumConfigurations = 0x01,
|
||||
};
|
||||
|
||||
static const struct usb_configuration_descriptor configuration_descriptor = {
|
||||
.bLength = 9, //sizeof(struct usb_configuration_descriptor),
|
||||
.bDescriptorType = DT_CONFIGURATION,
|
||||
.wTotalLength = (9 + /*9 + 9 + 7 +*/ 9 + 9 + 7 + 7) /*
|
||||
(sizeof(struct usb_configuration_descriptor)
|
||||
+ sizeof(struct usb_interface_descriptor)
|
||||
+ sizeof(struct usb_hid_descriptor)
|
||||
+ sizeof(struct usb_endpoint_descriptor)*/,
|
||||
.bNumInterfaces = 1,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = 5,
|
||||
.bmAttributes = 0x80, /* Remote wakeup not supported */
|
||||
.bMaxPower = 100 / 2, /* 100 mA (in 2-mA units) */
|
||||
.data = {
|
||||
/* struct usb_interface_descriptor { */
|
||||
/* uint8_t bLength; */ 9,
|
||||
/* uint8_t bDescriptorType; */ DT_INTERFACE,
|
||||
/* uint8_t bInterfaceNumber; */ 0,
|
||||
/* uint8_t bAlternateSetting; */ 0,
|
||||
/* uint8_t bNumEndpoints; */ 2, /* Two extra EPs */
|
||||
/* uint8_t bInterfaceClass; */ 3, /* HID class */
|
||||
/* uint8_t bInterfaceSubclass; */ 0, /* Boot Device subclass */
|
||||
/* uint8_t bInterfaceProtocol; */ 0, /* 1 == keyboard, 2 == mouse */
|
||||
/* uint8_t iInterface; */ 4, /* String index #4 */
|
||||
/* }*/
|
||||
|
||||
/* struct usb_hid_descriptor { */
|
||||
/* uint8_t bLength; */ 9,
|
||||
/* uint8_t bDescriptorType; */ DT_HID,
|
||||
/* uint16_t bcdHID; */ 0x11, 0x01,
|
||||
/* uint8_t bCountryCode; */ 0,
|
||||
/* uint8_t bNumDescriptors; */ 1, /* We have only one REPORT */
|
||||
/* uint8_t bReportDescriptorType; */ DT_HID_REPORT,
|
||||
/* uint16_t wReportDescriptorLength; */ sizeof(hid_report_descriptor),
|
||||
sizeof(hid_report_descriptor) >> 8,
|
||||
/* } */
|
||||
|
||||
/* struct usb_endpoint_descriptor { */
|
||||
/* uint8_t bLength; */ 7,
|
||||
/* uint8_t bDescriptorType; */ DT_ENDPOINT,
|
||||
/* uint8_t bEndpointAddress; */ 0x81, /* EP1 (IN) */
|
||||
/* uint8_t bmAttributes; */ 3, /* Interrupt */
|
||||
/* uint16_t wMaxPacketSize; */ 0x08, 0x00,
|
||||
/* uint8_t bInterval; */ EP_INTERVAL_MS, /* Every 6 ms */
|
||||
/* } */
|
||||
|
||||
/* struct usb_endpoint_descriptor { */
|
||||
/* uint8_t bLength; */ 7,
|
||||
/* uint8_t bDescriptorType; */ DT_ENDPOINT,
|
||||
/* uint8_t bEndpointAddress; */ 0x01, /* EP1 (OUT) */
|
||||
/* uint8_t bmAttributes; */ 3, /* Interrupt */
|
||||
/* uint16_t wMaxPacketSize; */ 0x08, 0x00,
|
||||
/* uint8_t bInterval; */ EP_INTERVAL_MS, /* Every 6 ms */
|
||||
/* } */
|
||||
},
|
||||
};
|
||||
|
||||
enum epfifo_response {
|
||||
EPF_ACK = 0,
|
||||
EPF_NAK = 1,
|
||||
@ -118,7 +39,7 @@ void usb_connect(void) {
|
||||
|
||||
// By default, it wants to respond with NAK.
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
|
||||
usb_ep_0_out_ev_pending_write(usb_ep_0_out_ev_enable_read());
|
||||
usb_ep_0_in_ev_pending_write(usb_ep_0_in_ev_pending_read());
|
||||
@ -134,11 +55,12 @@ void usb_init(void) {
|
||||
|
||||
volatile int irq_count = 0;
|
||||
|
||||
#define EP0OUT_BUFFERS 64
|
||||
#define EP0OUT_BUFFERS 4
|
||||
__attribute__((aligned(4)))
|
||||
static uint8_t usb_ep0out_buffer[EP0OUT_BUFFERS][128];
|
||||
static uint8_t usb_ep0out_buffer_len[EP0OUT_BUFFERS];
|
||||
uint8_t usb_ep0out_wr_ptr;
|
||||
uint8_t usb_ep0out_rd_ptr;
|
||||
int descriptor_ptr;
|
||||
int max_byte_length = 8;
|
||||
|
||||
static const uint8_t *current_data;
|
||||
@ -146,7 +68,7 @@ static int current_length;
|
||||
static int current_offset;
|
||||
static int current_to_send;
|
||||
|
||||
static int maybe_send_more_data(int epnum) {
|
||||
static int queue_more_data(int epnum) {
|
||||
(void)epnum;
|
||||
// Don't allow requeueing
|
||||
if (usb_ep_0_in_respond_read() != EPF_NAK)
|
||||
@ -157,22 +79,23 @@ static int maybe_send_more_data(int epnum) {
|
||||
if (current_to_send > max_byte_length)
|
||||
current_to_send = max_byte_length;
|
||||
|
||||
for (this_offset = current_offset; this_offset < current_offset + current_to_send; this_offset++) {
|
||||
for (this_offset = current_offset; this_offset < (current_offset + current_to_send); this_offset++) {
|
||||
usb_ep_0_in_ibuf_head_write(current_data[this_offset]);
|
||||
}
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_data(int epnum, const void *data, int total_count) {
|
||||
int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count) {
|
||||
(void)dev;
|
||||
// Don't allow requeueing
|
||||
if (usb_ep_0_in_respond_read() != EPF_NAK)
|
||||
return -1;
|
||||
current_data = (uint8_t *)data;
|
||||
current_length = total_count;
|
||||
current_offset = 0;
|
||||
maybe_send_more_data(epnum);
|
||||
control_state = IN_DATA;
|
||||
queue_more_data(epnum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -182,56 +105,48 @@ void usb_isr(void) {
|
||||
uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read();
|
||||
uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read();
|
||||
|
||||
// We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer
|
||||
// and clear the "pending" bit.
|
||||
if (ep0o_pending) {
|
||||
|
||||
int byte_count = 0;
|
||||
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr];
|
||||
while (1) {
|
||||
if (usb_ep_0_out_obuf_empty_read())
|
||||
break;
|
||||
obuf[++byte_count] = usb_ep_0_out_obuf_head_read();
|
||||
while (!usb_ep_0_out_obuf_empty_read()) {
|
||||
obuf[byte_count++] = usb_ep_0_out_obuf_head_read();
|
||||
usb_ep_0_out_obuf_head_write(0);
|
||||
}
|
||||
usb_ep_0_out_ev_pending_write(ep0o_pending);
|
||||
|
||||
if (byte_count) {
|
||||
obuf[0] = byte_count;
|
||||
printf("read %d bytes\n", byte_count);
|
||||
usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count;
|
||||
usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
|
||||
// usb_ep_0_in_dtb_write(1);
|
||||
send_data(0, &device_descriptor, sizeof(device_descriptor));
|
||||
}
|
||||
else {
|
||||
printf("read no bytes\n");
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
}
|
||||
|
||||
// We just got an "IN" token. Send data if we have it.
|
||||
if (ep0i_pending) {
|
||||
/*
|
||||
uint8_t *descriptor = (uint8_t *)&device_descriptor;
|
||||
if (descriptor_ptr < 0) {
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
}
|
||||
else if (descriptor_ptr >= sizeof(device_descriptor)) {
|
||||
descriptor_ptr = -1;
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
}
|
||||
else {
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
for (descriptor_ptr; descriptor_ptr < sizeof(device_descriptor); descriptor_ptr++) {
|
||||
usb_ep_0_in_ibuf_head_write(descriptor[descriptor_ptr]);
|
||||
}
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
}
|
||||
*/
|
||||
usb_ep_0_in_respond_write(EPF_NAK);
|
||||
current_offset += current_to_send;
|
||||
maybe_send_more_data(0);
|
||||
queue_more_data(0);
|
||||
usb_ep_0_in_ev_pending_write(ep0i_pending);
|
||||
|
||||
// Get ready to respond to the empty data byte
|
||||
// Get ready to respond with an empty data byte
|
||||
if (current_offset >= current_length) {
|
||||
current_offset = 0;
|
||||
current_length = 0;
|
||||
current_data = NULL;
|
||||
if (control_state == IN_DATA) {
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf(">> %02x %02x <<\n", ep0o_pending, ep0i_pending);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -244,335 +159,69 @@ int usb_irq_happened(void) {
|
||||
return irq_count;
|
||||
}
|
||||
|
||||
int usb_ack(struct usb_device *dev, int epnum) {
|
||||
usb_ep_0_out_respond_write(EPF_ACK);
|
||||
usb_ep_0_in_respond_write(EPF_ACK);
|
||||
}
|
||||
|
||||
int usb_err(struct usb_device *dev, int epnum) {
|
||||
usb_ep_0_out_respond_write(EPF_STALL);
|
||||
usb_ep_0_in_respond_write(EPF_STALL);
|
||||
}
|
||||
|
||||
int usb_recv(struct usb_device *dev, void *buffer, unsigned int buffer_len) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
|
||||
void usb_poll(void) {
|
||||
// If some data was received, then process it.
|
||||
if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]);
|
||||
|
||||
usb_setup(NULL, request);
|
||||
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
}
|
||||
// Cancel any pending transfers
|
||||
if ((control_state == IN_DATA) && usb_ep_0_in_ibuf_empty_read()) {
|
||||
printf("state is IN_DATA but ibuf is empty?\n");
|
||||
usb_ack(NULL, 0);
|
||||
printf("and obuf_empty_read(): %d\n", usb_ep_0_out_obuf_empty_read());
|
||||
usb_ep_0_out_obuf_head_write(0);
|
||||
control_state = WAIT_SETUP;
|
||||
}
|
||||
if (!usb_ep_0_out_obuf_empty_read()) {
|
||||
printf("obuf not empty\n");
|
||||
}
|
||||
// if (!usb_ep_0_in_ibuf_empty_read()) {
|
||||
// usb_ep_0_in_ibuf_head_write(0);
|
||||
// }
|
||||
// usb_ack(NULL, 0);
|
||||
}
|
||||
|
||||
void usb_print_status(void) {
|
||||
/*
|
||||
printf("EP0_OUT Status: %02x\n", usb_ep_0_out_ev_status_read());
|
||||
printf("EP0_OUT Pending: %02x\n", usb_ep_0_out_ev_pending_read());
|
||||
printf("EP0_OUT Enable: %02x\n", usb_ep_0_out_ev_enable_read());
|
||||
printf("EP0_OUT Last Tok: %02x\n", usb_ep_0_out_last_tok_read());
|
||||
printf("EP0_OUT Respond: %02x\n", usb_ep_0_out_respond_read());
|
||||
printf("EP0_OUT DTB: %02x\n", usb_ep_0_out_dtb_read());
|
||||
printf("EP0_OUT OBUF Head: %02x\n", usb_ep_0_out_obuf_head_read());
|
||||
printf("EP0_OUT OBUF Empty: %02x\n", usb_ep_0_out_obuf_empty_read());
|
||||
printf("EP0_IN Status: %02x\n", usb_ep_0_in_ev_status_read());
|
||||
printf("EP0_IN Pending: %02x\n", usb_ep_0_in_ev_pending_read());
|
||||
printf("EP0_IN Enable: %02x\n", usb_ep_0_in_ev_enable_read());
|
||||
printf("EP0_IN Last Tok: %02x\n", usb_ep_0_in_last_tok_read());
|
||||
printf("EP0_IN Respond: %02x\n", usb_ep_0_in_respond_read());
|
||||
printf("EP0_IN DTB: %02x\n", usb_ep_0_in_dtb_read());
|
||||
printf("EP0_IN IBUF Head: %02x\n", usb_ep_0_in_ibuf_head_read());
|
||||
printf("EP0_IN IBUF Empty: %02x\n", usb_ep_0_in_ibuf_empty_read());
|
||||
*/
|
||||
while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) {
|
||||
// printf("for (this_offset = current_offset; this_offset < this_offset + current_to_send; this_offset++) {\n");
|
||||
// printf("for (this_offset = %d; this_offset < %d; %d++) {\n", current_offset, this_offset, this_offset + current_to_send, this_offset);
|
||||
printf("current_data: 0x%08x\n", current_data);
|
||||
printf("current_length: %d\n", current_length);
|
||||
printf("current_offset: %d\n", current_offset);
|
||||
printf("current_to_send: %d\n", current_to_send);
|
||||
// printf("current_data: 0x%08x\n", current_data);
|
||||
// printf("current_length: %d\n", current_length);
|
||||
// printf("current_offset: %d\n", current_offset);
|
||||
// printf("current_to_send: %d\n", current_to_send);
|
||||
uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_rd_ptr];
|
||||
uint8_t cnt = obuf[0];
|
||||
uint8_t cnt = usb_ep0out_buffer_len[usb_ep0out_rd_ptr];
|
||||
unsigned int i;
|
||||
if (cnt) {
|
||||
for (i = 0; i < cnt; i++) {
|
||||
uart_write(' ');
|
||||
uart_write(hex[(obuf[i+1] >> 4) & 0xf]);
|
||||
uart_write(hex[obuf[i+1] & (0xf)]);
|
||||
// printf(" %02x", obufbuf[i]);
|
||||
}
|
||||
uart_write('\r');
|
||||
uart_write('\n');
|
||||
}
|
||||
// printf("\n");
|
||||
usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0;
|
||||
usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static inline unsigned char usb_pullup_out_read(void);
|
||||
// static inline void usb_pullup_out_write(unsigned char value);
|
||||
|
||||
|
||||
// static inline unsigned char usb_ep_0_out_ev_status_read(void);
|
||||
// static inline void usb_ep_0_out_ev_status_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_out_ev_pending_read(void);
|
||||
// static inline void usb_ep_0_out_ev_pending_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_out_ev_enable_read(void);
|
||||
// static inline void usb_ep_0_out_ev_enable_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_out_last_tok_read(void);
|
||||
|
||||
// static inline unsigned char usb_ep_0_out_respond_read(void);
|
||||
// static inline void usb_ep_0_out_respond_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_out_dtb_read(void);
|
||||
// static inline void usb_ep_0_out_dtb_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_out_obuf_head_read(void);
|
||||
// static inline void usb_ep_0_out_obuf_head_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_out_obuf_empty_read(void);
|
||||
|
||||
|
||||
// static inline unsigned char usb_ep_0_in_ev_status_read(void);
|
||||
// static inline void usb_ep_0_in_ev_status_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_in_ev_pending_read(void);
|
||||
// static inline void usb_ep_0_in_ev_pending_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_in_ev_enable_read(void);
|
||||
// static inline void usb_ep_0_in_ev_enable_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_in_last_tok_read(void);
|
||||
|
||||
// static inline unsigned char usb_ep_0_in_respond_read(void);
|
||||
// static inline void usb_ep_0_in_respond_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_in_dtb_read(void);
|
||||
// static inline void usb_ep_0_in_dtb_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_in_ibuf_head_read(void);
|
||||
// static inline void usb_ep_0_in_ibuf_head_write(unsigned char value);
|
||||
|
||||
// static inline unsigned char usb_ep_0_in_ibuf_empty_read(void);
|
||||
|
||||
|
||||
#if 0
|
||||
static uint32_t rx_buffer[NUM_BUFFERS][BUFFER_SIZE / sizeof(uint32_t)];
|
||||
static uint8_t rx_buffer_head;
|
||||
static uint8_t rx_buffer_tail;
|
||||
|
||||
static uint32_t rx_buffer_queries = 0;
|
||||
static void set_usb_config_num(struct GrainuumUSB *usb, int configNum)
|
||||
{
|
||||
(void)usb;
|
||||
(void)configNum;
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
#define USB_STR_BUF_LEN 64
|
||||
|
||||
static uint32_t str_buf_storage[USB_STR_BUF_LEN / sizeof(uint32_t)];
|
||||
static int send_string_descriptor(const char *str, const void **data)
|
||||
{
|
||||
int len;
|
||||
int max_len;
|
||||
uint8_t *str_buf = (uint8_t *)str_buf_storage;
|
||||
uint8_t *str_offset = str_buf;
|
||||
|
||||
len = strlen(str);
|
||||
max_len = (USB_STR_BUF_LEN / 2) - 2;
|
||||
|
||||
if (len > max_len)
|
||||
len = max_len;
|
||||
|
||||
*str_offset++ = (len * 2) + 2; // Two bytes for length count
|
||||
*str_offset++ = DT_STRING; // Sending a string descriptor
|
||||
|
||||
while (len--)
|
||||
{
|
||||
*str_offset++ = *str++;
|
||||
*str_offset++ = 0;
|
||||
}
|
||||
|
||||
*data = str_buf;
|
||||
|
||||
// Return the size, which is stored in the first byte of the output data.
|
||||
return str_buf[0];
|
||||
}
|
||||
|
||||
static int get_string_descriptor(struct GrainuumUSB *usb,
|
||||
uint32_t num,
|
||||
const void **data)
|
||||
{
|
||||
|
||||
static const uint8_t en_us[] = {0x04, DT_STRING, 0x09, 0x04};
|
||||
|
||||
(void)usb;
|
||||
|
||||
if (num == 0)
|
||||
{
|
||||
*data = en_us;
|
||||
return sizeof(en_us);
|
||||
}
|
||||
|
||||
// Product
|
||||
if (num == 1)
|
||||
return send_string_descriptor("Palawan Bootloader", data);
|
||||
|
||||
if (num == 2)
|
||||
return send_string_descriptor("21", data);
|
||||
|
||||
if (num == 3)
|
||||
return send_string_descriptor("1236", data);
|
||||
|
||||
if (num == 4)
|
||||
return send_string_descriptor("12345", data);
|
||||
|
||||
if (num == 5)
|
||||
return send_string_descriptor("54", data);
|
||||
|
||||
if (num == 6)
|
||||
return send_string_descriptor("12345678901234", data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_device_descriptor(struct GrainuumUSB *usb,
|
||||
uint32_t num,
|
||||
const void **data)
|
||||
{
|
||||
|
||||
(void)usb;
|
||||
|
||||
if (num == 0)
|
||||
{
|
||||
*data = &device_descriptor;
|
||||
return sizeof(device_descriptor);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_hid_report_descriptor(struct GrainuumUSB *usb,
|
||||
uint32_t num,
|
||||
const void **data)
|
||||
{
|
||||
|
||||
(void)usb;
|
||||
|
||||
if (num == 0)
|
||||
{
|
||||
*data = &hid_report_descriptor;
|
||||
return sizeof(hid_report_descriptor);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_configuration_descriptor(struct GrainuumUSB *usb,
|
||||
uint32_t num,
|
||||
const void **data)
|
||||
{
|
||||
|
||||
(void)usb;
|
||||
|
||||
if (num == 0)
|
||||
{
|
||||
*data = &configuration_descriptor;
|
||||
return configuration_descriptor.wTotalLength;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_descriptor(struct GrainuumUSB *usb,
|
||||
const void *packet,
|
||||
const void **response)
|
||||
{
|
||||
|
||||
const struct usb_setup_packet *setup = packet;
|
||||
printf("In get_Descriptor()\n");
|
||||
switch (setup->wValueH)
|
||||
{
|
||||
case DT_DEVICE:
|
||||
printf("Returning device descriptor %d\n", setup->wValueL);
|
||||
return get_device_descriptor(usb, setup->wValueL, response);
|
||||
|
||||
case DT_STRING:
|
||||
printf("Returning string descriptor %d\n", setup->wValueL);
|
||||
return get_string_descriptor(usb, setup->wValueL, response);
|
||||
|
||||
case DT_CONFIGURATION:
|
||||
printf("Returning configuration descriptor %d\n", setup->wValueL);
|
||||
return get_configuration_descriptor(usb, setup->wValueL, response);
|
||||
|
||||
case DT_HID_REPORT:
|
||||
printf("Returning HID descriptor %d\n", setup->wValueL);
|
||||
return get_hid_report_descriptor(usb, setup->wValueL, response);
|
||||
}
|
||||
|
||||
printf("Returning no descriptor %d\n", setup->wValueL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *get_usb_rx_buffer(struct GrainuumUSB *usb,
|
||||
uint8_t epNum,
|
||||
int32_t *size)
|
||||
{
|
||||
(void)usb;
|
||||
(void)epNum;
|
||||
|
||||
if (size)
|
||||
*size = sizeof(rx_buffer[0]);
|
||||
rx_buffer_queries++;
|
||||
return rx_buffer[rx_buffer_head];
|
||||
}
|
||||
|
||||
static int received_data(struct GrainuumUSB *usb,
|
||||
uint8_t epNum,
|
||||
uint32_t bytes,
|
||||
const void *data)
|
||||
{
|
||||
(void)usb;
|
||||
(void)epNum;
|
||||
(void)bytes;
|
||||
(void)data;
|
||||
|
||||
if (epNum == 1)
|
||||
{
|
||||
rx_buffer_head = (rx_buffer_head + 1) & (NUM_BUFFERS - 1);
|
||||
}
|
||||
|
||||
/* Return 0, indicating this packet is complete. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_data_finished(struct GrainuumUSB *usb, int result)
|
||||
{
|
||||
(void)usb;
|
||||
(void)result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct GrainuumConfig cfg = {
|
||||
.getDescriptor = get_descriptor,
|
||||
.getReceiveBuffer = get_usb_rx_buffer,
|
||||
.receiveData = received_data,
|
||||
.sendDataFinished = send_data_finished,
|
||||
.setConfigNum = set_usb_config_num,
|
||||
};
|
||||
|
||||
// void usb_isr(void) {
|
||||
// // grainuumCaptureI(&usb, usb_buf);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// void usb_init(void) {
|
||||
// // grainuumInit(&usb, &cfg);
|
||||
// // grainuumConnect(&usb);
|
||||
// return;
|
||||
// }
|
||||
|
||||
void usbPhyWriteI(const struct GrainuumUSB *usb, const void *buffer, uint32_t size) {
|
||||
// (void)usb;
|
||||
// const uint8_t *ubuffer = (const uint8_t *)buffer;
|
||||
// uint32_t i = 0;
|
||||
// while (i < size)
|
||||
// usb_obuf_head_write(ubuffer[i]);
|
||||
}
|
||||
|
||||
int usbPhyReadI(const struct GrainuumUSB *usb, uint8_t *samples) {
|
||||
(void)usb;
|
||||
int count = 0;
|
||||
// while (!usb_ibuf_empty_read()) {
|
||||
// samples[count++] = usb_ibuf_head_read();
|
||||
// }
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
#endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */
|
Loading…
Reference in New Issue
Block a user