mirror of
git://projects.qi-hardware.com/ben-wpan.git
synced 2024-11-26 12:45:21 +02:00
atusb/fw3/: adaptation of the f32xbase USB stack
This commit is contained in:
parent
f4d299d22b
commit
da6677b3d9
108
atusb/fw3/Makefile
Normal file
108
atusb/fw3/Makefile
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#
|
||||||
|
# Makefile - Makefile of the ATUSB firmware
|
||||||
|
#
|
||||||
|
# Written 2010-2011 by Werner Almesberger
|
||||||
|
# Copyright 2010-2011 by Werner Almesberger
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
|
||||||
|
SHELL = /bin/bash
|
||||||
|
|
||||||
|
NAME = atusb
|
||||||
|
|
||||||
|
CFLAGS = -g -Wall -Wextra -Wshadow -Werror -Wno-unused \
|
||||||
|
-Wmissing-prototypes -Wmissing-declarations -Wstrict-prototypes
|
||||||
|
|
||||||
|
CHIP=atmega32u2
|
||||||
|
|
||||||
|
AVR_PREFIX = $(BIN_PATH) avr-
|
||||||
|
CC = $(AVR_PREFIX)gcc
|
||||||
|
OBJCOPY = $(AVR_PREFIX)objcopy
|
||||||
|
#OBJDUMP = $(AVR_PREFIX)objdump
|
||||||
|
|
||||||
|
FreakUSB = usb
|
||||||
|
#USB_OBJS = usb.o ctrl.o usb_buf.o ep.o hw.o isr.o
|
||||||
|
USB_OBJS = usb.o
|
||||||
|
OBJS = atusb.o board.o spi.o descr.o ep0.o $(USB_OBJS)
|
||||||
|
|
||||||
|
#vpath %.c $(FreakUSB)/usb/
|
||||||
|
#vpath %.c $(FreakUSB)/hw/at90usbxx2/
|
||||||
|
vpath %.c usb2/
|
||||||
|
|
||||||
|
CFLAGS += -I../fw/include \
|
||||||
|
-Iusb2
|
||||||
|
-DNUM_EPS=1
|
||||||
|
# -I$(FreakUSB)/usb -I$(FreakUSB)/hw/at90usbxx2 \
|
||||||
|
|
||||||
|
# ----- Verbosity control -----------------------------------------------------
|
||||||
|
|
||||||
|
CC_normal := $(CC)
|
||||||
|
BUILD_normal :=
|
||||||
|
DEPEND_normal := $(CPP) $(CFLAGS) -MM -MG
|
||||||
|
|
||||||
|
CC_quiet = @echo " CC " $@ && $(CC_normal)
|
||||||
|
BUILD_quiet = @echo " BUILD " $@ && $(BUILD_normal)
|
||||||
|
DEPEND_quiet = @$(DEPEND_normal)
|
||||||
|
|
||||||
|
ifeq ($(V),1)
|
||||||
|
CC = $(CC_normal)
|
||||||
|
BUILD = $(BUILD_normal)
|
||||||
|
DEPEND = $(DEPEND_normal)
|
||||||
|
else
|
||||||
|
CC = $(CC_quiet)
|
||||||
|
BUILD = $(BUILD_quiet)
|
||||||
|
DEPEND = $(DEPEND_quiet)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# ----- Rules -----------------------------------------------------------------
|
||||||
|
|
||||||
|
.PHONY: all clean upload prog
|
||||||
|
|
||||||
|
all: $(NAME).bin
|
||||||
|
|
||||||
|
$(NAME).elf: $(OBJS)
|
||||||
|
$(CC) $(CFLAGS) -mmcu=$(CHIP) -o $@ $(OBJS)
|
||||||
|
|
||||||
|
%.bin: %.elf
|
||||||
|
$(BUILD) $(OBJCOPY) -j .text -j .data -O binary $< $@
|
||||||
|
|
||||||
|
# ----- Cleanup ---------------------------------------------------------------
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(NAME).bin $(NAME).elf $(OBJS) $(OBJS:.o=.d)
|
||||||
|
|
||||||
|
# ----- Dependencies ----------------------------------------------------------
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -mmcu=$(CHIP) -Os -c $<
|
||||||
|
$(DEPEND) $< | \
|
||||||
|
sed -e \
|
||||||
|
'/^\(.*:\)\? */{p;s///;s/ *\\\?$$/ /;s/ */:\n/g;H;}' \
|
||||||
|
-e '$${g;p;}' -e d >$*.d; \
|
||||||
|
[ "$${PIPESTATUS[*]}" = "0 0" ] || { rm -f $*.d; exit 1; }
|
||||||
|
|
||||||
|
-include $(OBJS:.o=.d)
|
||||||
|
|
||||||
|
# ----- Programming and device control ----------------------------------------
|
||||||
|
|
||||||
|
upload: $(NAME).bin
|
||||||
|
scp $(NAME).bin jlime:
|
||||||
|
|
||||||
|
prog:
|
||||||
|
ssh jlime avrdude -F -p $(CHIP) -c nanonote_atusb -e \
|
||||||
|
-U flash:w:$(NAME).bin:r \
|
||||||
|
-U lfuse:w:0x60:m # external clock, slow start-up
|
||||||
|
|
||||||
|
on:
|
||||||
|
ssh jlime poke 0x10010318 4
|
||||||
|
|
||||||
|
off:
|
||||||
|
ssh jlime poke 0x10010314 4
|
||||||
|
|
||||||
|
reset:
|
||||||
|
ssh jlime poke 0x10010318 2048
|
||||||
|
ssh jlime poke 0x10010314 2048
|
34
atusb/fw3/atusb.c
Normal file
34
atusb/fw3/atusb.c
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
#define F_CPU 8000000UL
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
#include "usb.h"
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "spi.h"
|
||||||
|
#include "atusb/ep0.h"
|
||||||
|
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
board_init();
|
||||||
|
spi_init();
|
||||||
|
reset_rf();
|
||||||
|
|
||||||
|
/* now we should be at 8 MHz */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
led(1);
|
||||||
|
_delay_ms(100);
|
||||||
|
led(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
usb_init();
|
||||||
|
ep0_init();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
usb_poll();
|
||||||
|
}
|
54
atusb/fw3/board.h
Normal file
54
atusb/fw3/board.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef BOARD_H
|
||||||
|
#define BOARD_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define LED_PORT B
|
||||||
|
#define LED_BIT 6
|
||||||
|
#define nRST_RF_PORT C
|
||||||
|
#define nRST_RF_BIT 7
|
||||||
|
#define SLP_TR_PORT B
|
||||||
|
#define SLP_TR_BIT 4
|
||||||
|
|
||||||
|
#define SCLK_PORT D
|
||||||
|
#define SCLK_BIT 5
|
||||||
|
#define MOSI_PORT D
|
||||||
|
#define MOSI_BIT 3
|
||||||
|
|
||||||
|
#define MISO_PORT D
|
||||||
|
#define MISO_BIT 2
|
||||||
|
#define nSS_PORT D
|
||||||
|
#define nSS_BIT 1
|
||||||
|
#define IRQ_RF_PORT D
|
||||||
|
#define IRQ_RF_BIT 0
|
||||||
|
|
||||||
|
|
||||||
|
#define SET_2(p, b) PORT##p |= 1 << (b)
|
||||||
|
#define CLR_2(p, b) PORT##p &= ~(1 << (b))
|
||||||
|
#define IN_2(p, b) DDR##p &= ~(1 << (b))
|
||||||
|
#define OUT_2(p, b) DDR##p |= 1 << (b)
|
||||||
|
#define PIN_2(p, b) ((PIN##p >> (b)) & 1)
|
||||||
|
|
||||||
|
#define SET_1(p, b) SET_2(p, b)
|
||||||
|
#define CLR_1(p, b) CLR_2(p, b)
|
||||||
|
#define IN_1(p, b) IN_2(p, b)
|
||||||
|
#define OUT_1(p, b) OUT_2(p, b)
|
||||||
|
#define PIN_1(p, b) PIN_2(p, b)
|
||||||
|
|
||||||
|
#define SET(n) SET_1(n##_PORT, n##_BIT)
|
||||||
|
#define CLR(n) CLR_1(n##_PORT, n##_BIT)
|
||||||
|
#define IN(n) IN_1(n##_PORT, n##_BIT)
|
||||||
|
#define OUT(n) OUT_1(n##_PORT, n##_BIT)
|
||||||
|
#define PIN(n) PIN_1(n##_PORT, n##_BIT)
|
||||||
|
|
||||||
|
void reset_rf(void);
|
||||||
|
uint8_t read_irq(void);
|
||||||
|
void led(int on);
|
||||||
|
void panic(void);
|
||||||
|
void board_init(void);
|
||||||
|
|
||||||
|
void rf_init(void);
|
||||||
|
void rf_send(const char *s);
|
||||||
|
|
||||||
|
#endif /* !BOARD_H */
|
99
atusb/fw3/descr.c
Normal file
99
atusb/fw3/descr.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* atspi/descr.c - USB descriptors
|
||||||
|
*
|
||||||
|
* Written 2008-2011 by Werner Almesberger
|
||||||
|
* Copyright 2008-2011 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "usb.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define USB_VENDOR 0x20b7 /* Qi Hardware */
|
||||||
|
#define USB_PRODUCT 0x1540 /* ben-wpan atusb */
|
||||||
|
|
||||||
|
#define LE(x) ((uint16_t) (x) & 0xff), ((uint16_t) (x) >> 8)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device descriptor
|
||||||
|
*/
|
||||||
|
|
||||||
|
const uint8_t device_descriptor[18] = {
|
||||||
|
18, /* bLength */
|
||||||
|
USB_DT_DEVICE, /* bDescriptorType */
|
||||||
|
LE(0x200), /* bcdUSB */
|
||||||
|
USB_CLASS_VENDOR_SPEC, /* bDeviceClass */
|
||||||
|
0x00, /* bDeviceSubClass */
|
||||||
|
0x00, /* bDeviceProtocol */
|
||||||
|
EP0_SIZE, /* bMaxPacketSize */
|
||||||
|
LE(USB_VENDOR), /* idVendor */
|
||||||
|
LE(USB_PRODUCT), /* idProduct */
|
||||||
|
LE(0x0001), /* bcdDevice */
|
||||||
|
0, /* iManufacturer */
|
||||||
|
0, /* iProduct */
|
||||||
|
0, /* iSerialNumber */
|
||||||
|
1 /* bNumConfigurations */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Our configuration
|
||||||
|
*
|
||||||
|
* We're always bus-powered.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const uint8_t config_descriptor[] = {
|
||||||
|
9, /* bLength */
|
||||||
|
USB_DT_CONFIG, /* bDescriptorType */
|
||||||
|
#if 0
|
||||||
|
LE(9+9+7+7), /* wTotalLength */
|
||||||
|
#else
|
||||||
|
LE(9+9), /* wTotalLength */
|
||||||
|
#endif
|
||||||
|
1, /* bNumInterfaces */
|
||||||
|
1, /* bConfigurationValue (> 0 !) */
|
||||||
|
0, /* iConfiguration */
|
||||||
|
USB_ATTR_BUS_POWERED, /* bmAttributes */
|
||||||
|
50/2, /* bMaxPower (50 mA) */
|
||||||
|
|
||||||
|
/* Interface #0 */
|
||||||
|
|
||||||
|
9, /* bLength */
|
||||||
|
USB_DT_INTERFACE, /* bDescriptorType */
|
||||||
|
0, /* bInterfaceNumber */
|
||||||
|
0, /* bAlternateSetting */
|
||||||
|
#if 0
|
||||||
|
2, /* bNumEndpoints */
|
||||||
|
#else
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
|
USB_CLASS_VENDOR_SPEC, /* bInterfaceClass */
|
||||||
|
0, /* bInterfaceSubClass */
|
||||||
|
0, /* bInterfaceProtocol */
|
||||||
|
0, /* iInterface */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* EP OUT */
|
||||||
|
|
||||||
|
7, /* bLength */
|
||||||
|
USB_DT_ENDPOINT, /* bDescriptorType */
|
||||||
|
0x01, /* bEndPointAddress */
|
||||||
|
0x02, /* bmAttributes (bulk) */
|
||||||
|
LE(EP1_SIZE), /* wMaxPacketSize */
|
||||||
|
0, /* bInterval */
|
||||||
|
|
||||||
|
/* EP IN */
|
||||||
|
|
||||||
|
7, /* bLength */
|
||||||
|
USB_DT_ENDPOINT, /* bDescriptorType */
|
||||||
|
0x81, /* bEndPointAddress */
|
||||||
|
0x02, /* bmAttributes (bulk) */
|
||||||
|
LE(EP1_SIZE), /* wMaxPacketSize */
|
||||||
|
0, /* bInterval */
|
||||||
|
#endif
|
||||||
|
};
|
194
atusb/fw3/ep0.c
Normal file
194
atusb/fw3/ep0.c
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* atspi/ep0.c - EP0 extension protocol
|
||||||
|
*
|
||||||
|
* Written 2008-2010 by Werner Almesberger
|
||||||
|
* Copyright 2008-2010 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include "regs.h"
|
||||||
|
//#include "uart.h"
|
||||||
|
//#include "usb.h"
|
||||||
|
|
||||||
|
#include "usb.h"
|
||||||
|
|
||||||
|
#include "at86rf230.h"
|
||||||
|
#include "atusb/ep0.h"
|
||||||
|
//#include "version.h"
|
||||||
|
#include "board.h"
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define HW_TYPE HW_TYPE_110131
|
||||||
|
static const char *build_date = "today";
|
||||||
|
static unsigned build_number = 42;
|
||||||
|
|
||||||
|
#define debug(...)
|
||||||
|
#define error(...)
|
||||||
|
|
||||||
|
|
||||||
|
static const uint8_t id[] = { EP0ATUSB_MAJOR, EP0ATUSB_MINOR, HW_TYPE };
|
||||||
|
static uint8_t buf[MAX_PSDU+3]; /* command, PHDR, and LQI */
|
||||||
|
static uint8_t size;
|
||||||
|
|
||||||
|
|
||||||
|
static void do_buf_write(void *user)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
spi_begin();
|
||||||
|
for (i = 0; i != size; i++)
|
||||||
|
spi_send(buf[i]);
|
||||||
|
spi_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define BUILD_OFFSET 7 /* '#' plus "65535" plus ' ' */
|
||||||
|
|
||||||
|
|
||||||
|
static int my_setup(struct setup_request *setup)
|
||||||
|
{
|
||||||
|
unsigned tmp;
|
||||||
|
uint8_t i;
|
||||||
|
|
||||||
|
switch (setup->bmRequestType | setup->bRequest << 8) {
|
||||||
|
case ATUSB_FROM_DEV(ATUSB_ID):
|
||||||
|
debug("ATUSB_ID\n");
|
||||||
|
if (setup->wLength > 3)
|
||||||
|
return 0;
|
||||||
|
usb_send(&eps[0], id, setup->wLength, NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
case ATUSB_FROM_DEV(ATUSB_BUILD):
|
||||||
|
debug("ATUSB_BUILD\n");
|
||||||
|
tmp = build_number;
|
||||||
|
for (i = BUILD_OFFSET-2; tmp; i--) {
|
||||||
|
buf[i] = (tmp % 10)+'0';
|
||||||
|
tmp /= 10;
|
||||||
|
}
|
||||||
|
buf[i] = '#';
|
||||||
|
buf[BUILD_OFFSET-1] = ' ';
|
||||||
|
for (size = 0; build_date[size]; size++)
|
||||||
|
buf[BUILD_OFFSET+size] = build_date[size];
|
||||||
|
size += BUILD_OFFSET-i;
|
||||||
|
if (size > setup->wLength)
|
||||||
|
return 0;
|
||||||
|
usb_send(&eps[0], buf+i, size, NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
#ifdef NOTYET
|
||||||
|
case ATUSB_TO_DEV(ATUSB_RESET):
|
||||||
|
debug("ATUSB_RESET\n");
|
||||||
|
RSTSRC = SWRSF;
|
||||||
|
while (1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case ATUSB_TO_DEV(ATUSB_RF_RESET):
|
||||||
|
debug("ATUSB_RF_RESET\n");
|
||||||
|
reset_rf();
|
||||||
|
//ep_send_zlp(EP_CTRL);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case ATUSB_FROM_DEV(ATUSB_POLL_INT):
|
||||||
|
debug("ATUSB_POLL_INT\n");
|
||||||
|
if (setup->wLength < 1)
|
||||||
|
return 0;
|
||||||
|
*buf = read_irq();
|
||||||
|
usb_send(&eps[0], buf, 1, NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case ATUSB_TO_DEV(ATUSB_REG_WRITE):
|
||||||
|
debug("ATUSB_REG_WRITE\n");
|
||||||
|
spi_begin();
|
||||||
|
spi_send(AT86RF230_REG_WRITE | setup->wIndex);
|
||||||
|
spi_send(setup->wValue);
|
||||||
|
spi_end();
|
||||||
|
//ep_send_zlp(EP_CTRL);
|
||||||
|
return 1;
|
||||||
|
case ATUSB_FROM_DEV(ATUSB_REG_READ):
|
||||||
|
debug("ATUSB_REG_READ\n");
|
||||||
|
spi_begin();
|
||||||
|
spi_send(AT86RF230_REG_READ | setup->wIndex);
|
||||||
|
*buf = spi_recv();
|
||||||
|
spi_end();
|
||||||
|
usb_send(&eps[0], buf, 1, NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case ATUSB_TO_DEV(ATUSB_BUF_WRITE):
|
||||||
|
debug("ATUSB_BUF_WRITE\n");
|
||||||
|
if (setup->wLength < 1)
|
||||||
|
return 0;
|
||||||
|
if (setup->wLength > MAX_PSDU)
|
||||||
|
return 0;
|
||||||
|
buf[0] = AT86RF230_BUF_WRITE;
|
||||||
|
buf[1] = setup->wLength;
|
||||||
|
size = setup->wLength+2;
|
||||||
|
usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
|
||||||
|
return 1;
|
||||||
|
case ATUSB_FROM_DEV(ATUSB_BUF_READ):
|
||||||
|
debug("ATUSB_BUF_READ\n");
|
||||||
|
if (setup->wLength < 2) /* PHR+LQI */
|
||||||
|
return 0;
|
||||||
|
if (setup->wLength > MAX_PSDU+2) /* PHR+PSDU+LQI */
|
||||||
|
return 0;
|
||||||
|
spi_begin();
|
||||||
|
spi_send(AT86RF230_BUF_READ);
|
||||||
|
size = spi_recv();
|
||||||
|
if (size >= setup->wLength)
|
||||||
|
size = setup->wLength-1;
|
||||||
|
for (i = 0; i != size+1; i++)
|
||||||
|
buf[i] = spi_recv();
|
||||||
|
spi_end();
|
||||||
|
usb_send(&eps[0], buf, size+1, NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case ATUSB_TO_DEV(ATUSB_SRAM_WRITE):
|
||||||
|
debug("ATUSB_SRAM_WRITE\n");
|
||||||
|
if (setup->wIndex > SRAM_SIZE)
|
||||||
|
return 0;
|
||||||
|
if (setup->wIndex+setup->wLength > SRAM_SIZE)
|
||||||
|
return 0;
|
||||||
|
buf[0] = AT86RF230_SRAM_WRITE;
|
||||||
|
buf[1] = setup->wIndex;
|
||||||
|
size = setup->wLength+2;
|
||||||
|
usb_recv(&eps[0], buf+2, setup->wLength, do_buf_write, NULL);
|
||||||
|
return 1;
|
||||||
|
case ATUSB_TO_DEV(ATUSB_SRAM_READ):
|
||||||
|
debug("ATUSB_SRAM_READ\n");
|
||||||
|
if (setup->wIndex > SRAM_SIZE)
|
||||||
|
return 0;
|
||||||
|
if (setup->wIndex+setup->wLength > SRAM_SIZE)
|
||||||
|
return 0;
|
||||||
|
spi_begin();
|
||||||
|
spi_send(AT86RF230_SRAM_READ);
|
||||||
|
spi_send(setup->wIndex);
|
||||||
|
for (i = 0; i != size; i++)
|
||||||
|
buf[i] = spi_recv();
|
||||||
|
spi_end();
|
||||||
|
usb_send(&eps[0], buf, size, NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error("Unrecognized SETUP: 0x%02x 0x%02x ...\n",
|
||||||
|
setup->bmRequestType, setup->bRequest);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ep0_init(void)
|
||||||
|
{
|
||||||
|
user_setup = my_setup;
|
||||||
|
}
|
45
atusb/fw3/spi.c
Normal file
45
atusb/fw3/spi.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
#include "board.h"
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
|
||||||
|
void spi_begin(void)
|
||||||
|
{
|
||||||
|
CLR(nSS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t spi_io(uint8_t v)
|
||||||
|
{
|
||||||
|
// while (!(UCSR1A & 1 << UDRE1));
|
||||||
|
UDR1 = v;
|
||||||
|
while (!(UCSR1A & 1 << RXC1));
|
||||||
|
return UDR1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void spi_end(void)
|
||||||
|
{
|
||||||
|
// while (!(UCSR1A & 1 << TXC1));
|
||||||
|
SET(nSS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void spi_init(void)
|
||||||
|
{
|
||||||
|
SET(nSS);
|
||||||
|
OUT(SCLK);
|
||||||
|
OUT(MOSI);
|
||||||
|
OUT(nSS);
|
||||||
|
IN(MISO);
|
||||||
|
|
||||||
|
UBRR1 = 0; /* set bit rate to zero to begin */
|
||||||
|
UCSR1C = 1 << UMSEL11 | 1 << UMSEL10;
|
||||||
|
/* set MSPI, MSB first, SPI data mode 0 */
|
||||||
|
UCSR1B = 1 << RXEN1 | 1 << TXEN1;
|
||||||
|
/* enable receiver and transmitter */
|
||||||
|
UBRR1 = 0; /* reconfirm the bit rate */
|
||||||
|
}
|
15
atusb/fw3/spi.h
Normal file
15
atusb/fw3/spi.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef SPI_H
|
||||||
|
#define SPI_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
void spi_begin(void);
|
||||||
|
uint8_t spi_io(uint8_t v);
|
||||||
|
void spi_end(void);
|
||||||
|
void spi_init(void);
|
||||||
|
|
||||||
|
#define spi_send(v) (void) spi_io(v)
|
||||||
|
#define spi_recv(v) spi_io(0)
|
||||||
|
|
||||||
|
#endif /* !SPI_H */
|
349
atusb/fw3/usb2/usb.c
Normal file
349
atusb/fw3/usb2/usb.c
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
/*
|
||||||
|
* u/usb.c - USB hardware setup and standard device requests
|
||||||
|
*
|
||||||
|
* Written 2008-2011 by Werner Almesberger
|
||||||
|
* Copyright 2008-2011 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Known issues:
|
||||||
|
* - no suspend/resume
|
||||||
|
* - EP0-sized packets cause an (otherwise harmless) SUEND at the end of the
|
||||||
|
* packet
|
||||||
|
* - #ifdef hell
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code follows the register read/write sequences from the examples in
|
||||||
|
* SiLabs/MCU/Examples/C8051F326_7/USB_Interrupt/Firmware/F326_USB_Main.c and
|
||||||
|
* SiLabs/MCU/Examples/C8051F326_7/USB_Interrupt/Firmware/F326_USB_ISR.c
|
||||||
|
*
|
||||||
|
* More resources:
|
||||||
|
* http://www.beyondlogic.org/usbnutshell/usb1.htm
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define F_CPU 8000000UL
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "usb.h"
|
||||||
|
#include "../board.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NUM_EPS 1
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
extern void panic(void);
|
||||||
|
#define BUG_ON(cond) do { if (cond) panic(); } while (0)
|
||||||
|
#else
|
||||||
|
#define BUG_ON(cond)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ep_descr eps[5];
|
||||||
|
|
||||||
|
int (*user_setup)(struct setup_request *setup);
|
||||||
|
int (*user_get_descriptor)(uint8_t type, uint8_t index,
|
||||||
|
const uint8_t * const *reply, uint8_t *size);
|
||||||
|
void (*user_reset)(void);
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t addr;
|
||||||
|
|
||||||
|
|
||||||
|
void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
|
||||||
|
uint8_t size, void (*callback)(void *user), void *user)
|
||||||
|
{
|
||||||
|
BUG_ON(ep->state);
|
||||||
|
ep->state = state;
|
||||||
|
ep->buf = buf;
|
||||||
|
ep->end = buf+size;
|
||||||
|
ep->callback = callback;
|
||||||
|
ep->user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint16_t usb_read_word(void)
|
||||||
|
{
|
||||||
|
uint8_t low;
|
||||||
|
|
||||||
|
low = UEDATX;
|
||||||
|
return low | UEDATX << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int get_descriptor(uint8_t type, uint8_t index, uint16_t length)
|
||||||
|
{
|
||||||
|
const uint8_t *reply;
|
||||||
|
uint8_t size;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case USB_DT_DEVICE:
|
||||||
|
reply = device_descriptor;
|
||||||
|
size = reply[0];
|
||||||
|
break;
|
||||||
|
case USB_DT_CONFIG:
|
||||||
|
if (index)
|
||||||
|
return 0;
|
||||||
|
reply = config_descriptor;
|
||||||
|
size = reply[2];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!user_get_descriptor)
|
||||||
|
return 0;
|
||||||
|
if (!user_get_descriptor(type, index, &reply, &size))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (length < size)
|
||||||
|
size = length;
|
||||||
|
usb_send(&eps[0], reply, size, NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void enable_addr(void *user)
|
||||||
|
{
|
||||||
|
while (!(UEINTX & (1 << TXINI)));
|
||||||
|
UDADDR = addr | 1 << ADDEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process a SETUP packet. Hardware ensures that length is 8 bytes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static int handle_setup(void)
|
||||||
|
{
|
||||||
|
struct setup_request setup;
|
||||||
|
|
||||||
|
BUG_ON(UEBCLX < 8);
|
||||||
|
|
||||||
|
setup.bmRequestType = UEDATX;
|
||||||
|
setup.bRequest = UEDATX;
|
||||||
|
setup.wValue = usb_read_word();
|
||||||
|
setup.wIndex = usb_read_word();
|
||||||
|
setup.wLength = usb_read_word();
|
||||||
|
|
||||||
|
// UEINTX &= ~(1 << RXSTPI);
|
||||||
|
|
||||||
|
switch (setup.bmRequestType | setup.bRequest << 8) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device request
|
||||||
|
*
|
||||||
|
* See http://www.beyondlogic.org/usbnutshell/usb6.htm
|
||||||
|
*/
|
||||||
|
|
||||||
|
case FROM_DEVICE(GET_STATUS):
|
||||||
|
if (setup.wLength != 2)
|
||||||
|
return 0;
|
||||||
|
usb_send(&eps[0], "\000", 2, NULL, NULL);
|
||||||
|
break;
|
||||||
|
case TO_DEVICE(CLEAR_FEATURE):
|
||||||
|
break;
|
||||||
|
case TO_DEVICE(SET_FEATURE):
|
||||||
|
return 0;
|
||||||
|
case TO_DEVICE(SET_ADDRESS):
|
||||||
|
addr = setup.wValue;
|
||||||
|
UDADDR = addr;
|
||||||
|
usb_send(&eps[0], NULL, 0, enable_addr, NULL);
|
||||||
|
break;
|
||||||
|
case FROM_DEVICE(GET_DESCRIPTOR):
|
||||||
|
if (!get_descriptor(setup.wValue >> 8, setup.wValue,
|
||||||
|
setup.wLength))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case TO_DEVICE(SET_DESCRIPTOR):
|
||||||
|
return 0;
|
||||||
|
case FROM_DEVICE(GET_CONFIGURATION):
|
||||||
|
usb_send(&eps[0], "", 1, NULL, NULL);
|
||||||
|
break;
|
||||||
|
case TO_DEVICE(SET_CONFIGURATION):
|
||||||
|
if (setup.wValue != config_descriptor[5])
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interface request
|
||||||
|
*/
|
||||||
|
|
||||||
|
case FROM_INTERFACE(GET_STATUS):
|
||||||
|
return 0;
|
||||||
|
case TO_INTERFACE(CLEAR_FEATURE):
|
||||||
|
return 0;
|
||||||
|
case TO_INTERFACE(SET_FEATURE):
|
||||||
|
return 0;
|
||||||
|
case FROM_INTERFACE(GET_INTERFACE):
|
||||||
|
return 0;
|
||||||
|
case TO_INTERFACE(SET_INTERFACE):
|
||||||
|
{
|
||||||
|
const uint8_t *interface_descriptor =
|
||||||
|
config_descriptor+9;
|
||||||
|
|
||||||
|
if (setup.wIndex != interface_descriptor[2] ||
|
||||||
|
setup.wValue != interface_descriptor[3])
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Endpoint request
|
||||||
|
*/
|
||||||
|
|
||||||
|
case FROM_ENDPOINT(GET_STATUS):
|
||||||
|
return 0;
|
||||||
|
case TO_ENDPOINT(CLEAR_FEATURE):
|
||||||
|
return 0;
|
||||||
|
case TO_ENDPOINT(SET_FEATURE):
|
||||||
|
return 0;
|
||||||
|
case FROM_ENDPOINT(SYNCH_FRAME):
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (!user_setup)
|
||||||
|
return 0;
|
||||||
|
if (!user_setup(&setup))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(setup.bmRequestType & 0x80) && eps[0].state == EP_IDLE)
|
||||||
|
usb_send(&eps[0], NULL, 0, NULL, NULL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int ep_rx(struct ep_descr *ep)
|
||||||
|
{
|
||||||
|
uint8_t size;
|
||||||
|
|
||||||
|
size = UEBCLX;
|
||||||
|
if (size > ep->end-ep->buf)
|
||||||
|
return 0;
|
||||||
|
while (size--)
|
||||||
|
*ep->buf++ = UEDATX;
|
||||||
|
if (ep->buf == ep->end) {
|
||||||
|
ep->state = EP_IDLE;
|
||||||
|
if (ep->callback)
|
||||||
|
ep->callback(ep->user);
|
||||||
|
if (ep == &eps[0])
|
||||||
|
usb_send(ep, NULL, 0, NULL, NULL);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ep_tx(struct ep_descr *ep)
|
||||||
|
{
|
||||||
|
uint8_t size = ep->end-ep->buf;
|
||||||
|
uint8_t left;
|
||||||
|
|
||||||
|
if (size > ep->size)
|
||||||
|
size = ep->size;
|
||||||
|
for (left = size; left; left--)
|
||||||
|
UEDATX = *ep->buf++;
|
||||||
|
if (size == ep->size)
|
||||||
|
return;
|
||||||
|
ep->state = EP_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void handle_ep(int n)
|
||||||
|
{
|
||||||
|
struct ep_descr *ep = eps+n;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
UENUM = n;
|
||||||
|
if (UEINTX & (1 << RXSTPI)) {
|
||||||
|
/* @@@ EP_RX. EP_TX: cancel */
|
||||||
|
if (!handle_setup())
|
||||||
|
goto stall;
|
||||||
|
UEINTX &= ~(1 << RXSTPI);
|
||||||
|
}
|
||||||
|
if (UEINTX & (1 << RXOUTI)) {
|
||||||
|
/* @@ EP_TX: cancel */
|
||||||
|
if (ep->state != EP_RX)
|
||||||
|
goto stall;
|
||||||
|
if (!ep_rx(ep))
|
||||||
|
goto stall;
|
||||||
|
// UEINTX &= ~(1 << RXOUTI);
|
||||||
|
UEINTX &= ~(1 << RXOUTI | 1 << FIFOCON);
|
||||||
|
}
|
||||||
|
if (UEINTX & (1 << STALLEDI)) {
|
||||||
|
ep->state = EP_IDLE;
|
||||||
|
UEINTX &= ~(1 << STALLEDI);
|
||||||
|
}
|
||||||
|
if (UEINTX & (1 << TXINI)) {
|
||||||
|
/* @@ EP_RX: cancel */
|
||||||
|
if (ep->state == EP_TX) {
|
||||||
|
ep_tx(ep);
|
||||||
|
UEINTX &= ~(1 << TXINI);
|
||||||
|
if (ep->state == EP_IDLE && ep->callback)
|
||||||
|
ep->callback(ep->user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
stall:
|
||||||
|
UEINTX &= ~(1 << RXSTPI | 1 << RXOUTI | 1 << STALLEDI);
|
||||||
|
ep->state = EP_IDLE;
|
||||||
|
UECONX |= 1 << STALLRQ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void usb_poll(void)
|
||||||
|
{
|
||||||
|
uint8_t flags, i;
|
||||||
|
|
||||||
|
flags = UEINT;
|
||||||
|
for (i = 0; i != NUM_EPS; i++)
|
||||||
|
if (1 || flags & (1 << i))
|
||||||
|
handle_ep(i);
|
||||||
|
/* @@@ USB bus reset */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ep_init(void)
|
||||||
|
{
|
||||||
|
UENUM = 0;
|
||||||
|
UECONX = (1 << RSTDT) | (1 << EPEN); /* enable */
|
||||||
|
UECFG0X = 0; /* control, direction is ignored */
|
||||||
|
UECFG1X = 3 << EPSIZE0; /* 64 bytes */
|
||||||
|
UECFG1X |= 1 << ALLOC;
|
||||||
|
|
||||||
|
while (!(UESTA0X & (1 << CFGOK)));
|
||||||
|
|
||||||
|
eps[0].state = EP_IDLE;
|
||||||
|
eps[0].size = 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void usb_init(void)
|
||||||
|
{
|
||||||
|
USBCON |= 1 << FRZCLK; /* freeze the clock */
|
||||||
|
|
||||||
|
/* enable the PLL and wait for it to lock */
|
||||||
|
PLLCSR &= ~(1 << PLLP2 | 1 << PLLP1 | 1 << PLLP0);
|
||||||
|
PLLCSR |= 1 << PLLE;
|
||||||
|
while (!(PLLCSR & (1 << PLOCK)));
|
||||||
|
|
||||||
|
USBCON &= ~(1 << USBE); /* reset the controller */
|
||||||
|
USBCON |= 1 << USBE;
|
||||||
|
|
||||||
|
USBCON &= ~(1 << FRZCLK); /* thaw the clock */
|
||||||
|
|
||||||
|
UDCON &= ~(1 << DETACH); /* attach the pull-up */
|
||||||
|
UDCON |= 1 << RSTCPU; /* reset CPU on bus reset */
|
||||||
|
|
||||||
|
ep_init();
|
||||||
|
}
|
146
atusb/fw3/usb2/usb.h
Normal file
146
atusb/fw3/usb2/usb.h
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* common/usb.h - USB hardware setup and standard device requests
|
||||||
|
*
|
||||||
|
* Written 2008, 2009 by Werner Almesberger
|
||||||
|
* Copyright 2008, 2009 Werner Almesberger
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef USB_H
|
||||||
|
#define USB_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Descriptor types
|
||||||
|
*
|
||||||
|
* Reuse libusb naming scheme (/usr/include/usb.h)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define USB_DT_DEVICE 1
|
||||||
|
#define USB_DT_CONFIG 2
|
||||||
|
#define USB_DT_STRING 3
|
||||||
|
#define USB_DT_INTERFACE 4
|
||||||
|
#define USB_DT_ENDPOINT 5
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device classes
|
||||||
|
*
|
||||||
|
* Reuse libusb naming scheme (/usr/include/usb.h)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define USB_CLASS_PER_INTERFACE 0xfe
|
||||||
|
#define USB_CLASS_VENDOR_SPEC 0xff
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configuration attributes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define USB_ATTR_BUS_POWERED 0x80
|
||||||
|
#define USB_ATTR_SELF_POWERED 0x40
|
||||||
|
#define USB_ATTR_REMOTE_WAKEUP 0x20
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup request types
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TO_DEVICE(req) (0x00 | (req) << 8)
|
||||||
|
#define FROM_DEVICE(req) (0x80 | (req) << 8)
|
||||||
|
#define TO_INTERFACE(req) (0x01 | (req) << 8)
|
||||||
|
#define FROM_INTERFACE(req) (0x81 | (req) << 8)
|
||||||
|
#define TO_ENDPOINT(req) (0x02 | (req) << 8)
|
||||||
|
#define FROM_ENDPOINT(req) (0x82 | (req) << 8)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup requests
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GET_STATUS 0x00
|
||||||
|
#define CLEAR_FEATURE 0x01
|
||||||
|
#define SET_FEATURE 0x03
|
||||||
|
#define SET_ADDRESS 0x05
|
||||||
|
#define GET_DESCRIPTOR 0x06
|
||||||
|
#define SET_DESCRIPTOR 0x07
|
||||||
|
#define GET_CONFIGURATION 0x08
|
||||||
|
#define SET_CONFIGURATION 0x09
|
||||||
|
#define GET_INTERFACE 0x0a
|
||||||
|
#define SET_INTERFACE 0x0b
|
||||||
|
#define SYNCH_FRAME 0x0c
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Odd. sdcc seems to think "x" assumes the size of the destination, i.e.,
|
||||||
|
* uint8_t. Hence the cast.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LE(x) ((uint16_t) (x) & 0xff), ((uint16_t) (x) >> 8)
|
||||||
|
|
||||||
|
#define LO(x) (((uint8_t *) &(x))[0])
|
||||||
|
#define HI(x) (((uint8_t *) &(x))[1])
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LOW_SPEED
|
||||||
|
#define EP0_SIZE 8
|
||||||
|
#else
|
||||||
|
#define EP0_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EP1_SIZE 64 /* simplify */
|
||||||
|
|
||||||
|
|
||||||
|
enum ep_state {
|
||||||
|
EP_IDLE,
|
||||||
|
EP_RX,
|
||||||
|
EP_TX,
|
||||||
|
EP_STALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ep_descr {
|
||||||
|
enum ep_state state;
|
||||||
|
uint8_t *buf;
|
||||||
|
uint8_t *end;
|
||||||
|
uint8_t size;
|
||||||
|
void (*callback)(void *user);
|
||||||
|
void *user;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct setup_request {
|
||||||
|
uint8_t bmRequestType;
|
||||||
|
uint8_t bRequest;
|
||||||
|
uint16_t wValue;
|
||||||
|
uint16_t wIndex;
|
||||||
|
uint16_t wLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern const uint8_t device_descriptor[];
|
||||||
|
extern const uint8_t config_descriptor[];
|
||||||
|
extern struct ep_descr eps[];
|
||||||
|
|
||||||
|
extern int (*user_setup)(struct setup_request *setup);
|
||||||
|
extern int (*user_get_descriptor)(uint8_t type, uint8_t index,
|
||||||
|
const uint8_t * const *reply, uint8_t *size);
|
||||||
|
extern void (*user_reset)(void);
|
||||||
|
|
||||||
|
|
||||||
|
#define usb_left(ep) ((ep)->end-(ep)->buf)
|
||||||
|
#define usb_send(ep, buf, size, callback, user) \
|
||||||
|
usb_io(ep, EP_TX, (void *) buf, size, callback, user)
|
||||||
|
#define usb_recv(ep, buf, size, callback, user) \
|
||||||
|
usb_io(ep, EP_RX, buf, size, callback, user)
|
||||||
|
|
||||||
|
void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf,
|
||||||
|
uint8_t size, void (*callback)(void *user), void *user);
|
||||||
|
|
||||||
|
|
||||||
|
void usb_init(void);
|
||||||
|
void usb_poll(void);
|
||||||
|
|
||||||
|
#endif /* !USB_H */
|
Loading…
Reference in New Issue
Block a user