187
									
								
								src/grainuum-phy.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								src/grainuum-phy.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,187 @@
 | 
			
		||||
/****************************************************************************
 | 
			
		||||
 * 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>
 | 
			
		||||
 | 
			
		||||
__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])
 | 
			
		||||
{
 | 
			
		||||
  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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int grainuumInitialized(struct GrainuumUSB *usb)
 | 
			
		||||
{
 | 
			
		||||
  if (!usb)
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
  return usb->initialized;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void grainuumWriteQueue(struct GrainuumUSB *usb, int epnum,
 | 
			
		||||
                        const void *buffer, int size)
 | 
			
		||||
{
 | 
			
		||||
  usb->queued_data = buffer;
 | 
			
		||||
  usb->queued_epnum = epnum;
 | 
			
		||||
  usb->queued_size = size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void grainuumInit(struct GrainuumUSB *usb,
 | 
			
		||||
                  struct GrainuumConfig *cfg) {
 | 
			
		||||
 | 
			
		||||
  if (usb->initialized)
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										362
									
								
								src/grainuum-state.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										362
									
								
								src/grainuum-state.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,362 @@
 | 
			
		||||
/****************************************************************************
 | 
			
		||||
 * 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"
 | 
			
		||||
 | 
			
		||||
#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 > 8)
 | 
			
		||||
    state->packet.size = 8;
 | 
			
		||||
  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 -= 8;
 | 
			
		||||
  state->data_out_max -= 8;
 | 
			
		||||
  state->data_out += 8;
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
  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 {
 | 
			
		||||
    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[10],
 | 
			
		||||
                               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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void grainuum_state_parse_token(struct GrainuumState *state,
 | 
			
		||||
                                       const uint8_t packet[2])
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  state->tok_epnum = (((const uint16_t *)packet)[0] >> 7) & 0xf;
 | 
			
		||||
  /*state->tok_addr  = (((const uint16_t *)packet)[0] >> 11) & 0x1f; // Field unused in this code*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void grainuumProcess(struct GrainuumUSB *usb,
 | 
			
		||||
                     const uint8_t packet[12])
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
  uint32_t size = packet[11];
 | 
			
		||||
  struct GrainuumState *state = &usb->state;
 | 
			
		||||
  switch(packet[0]) {
 | 
			
		||||
  case USB_PID_SETUP:
 | 
			
		||||
    state->packet_type = packet_type_setup;
 | 
			
		||||
    grainuum_state_clear_tx(state, 1);
 | 
			
		||||
    grainuum_state_parse_token(state, packet + 1);
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
  case USB_PID_DATA0:
 | 
			
		||||
    state->data_buffer |= (1 << state->tok_epnum);
 | 
			
		||||
    grainuum_state_parse_data(state, packet + 1, size - 1);
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
  case USB_PID_DATA1:
 | 
			
		||||
    state->data_buffer &= ~(1 << state->tok_epnum);
 | 
			
		||||
    grainuum_state_parse_data(state, packet + 1, size - 1);
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
  case USB_PID_OUT:
 | 
			
		||||
    grainuum_state_parse_token(state, packet + 1);
 | 
			
		||||
    state->packet_type = packet_type_out;
 | 
			
		||||
    state->tok_pos = 0;
 | 
			
		||||
    state->tok_buf = usb->cfg->getReceiveBuffer(usb, state->tok_epnum, NULL);
 | 
			
		||||
  break;
 | 
			
		||||
 | 
			
		||||
  case USB_PID_ACK:
 | 
			
		||||
    state->data_buffer ^= (1 << state->tok_epnum);
 | 
			
		||||
    usbStateTransferSuccess(state);
 | 
			
		||||
    if (state->data_out) {
 | 
			
		||||
      grainuum_state_process_tx(state);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      grainuum_state_clear_tx(state, 0);
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
  default:
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -27,6 +27,7 @@ static void init(void) {
 | 
			
		||||
    irq_setmask(0);
 | 
			
		||||
    irq_setie(1);
 | 
			
		||||
    uart_init();
 | 
			
		||||
    usb_init();
 | 
			
		||||
    init_printf(NULL, rv_putchar);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								src/usb.c
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								src/usb.c
									
									
									
									
									
								
							@@ -1,5 +1,34 @@
 | 
			
		||||
#include <grainuum.h>
 | 
			
		||||
#include <usb.h>
 | 
			
		||||
#include <generated/csr.h>
 | 
			
		||||
 | 
			
		||||
static struct GrainuumConfig cfg;
 | 
			
		||||
static struct GrainuumUSB usb;
 | 
			
		||||
static uint8_t usb_buf[67];
 | 
			
		||||
 | 
			
		||||
void usb_isr(void) {
 | 
			
		||||
    grainuumCaptureI(&usb, usb_buf);
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void usb_init(void) {
 | 
			
		||||
    grainuumInit(&usb, &cfg);
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user