diff --git a/atusb/fw3/Makefile b/atusb/fw3/Makefile index 8479b89..4567230 100644 --- a/atusb/fw3/Makefile +++ b/atusb/fw3/Makefile @@ -24,7 +24,7 @@ CC = $(AVR_PREFIX)gcc OBJCOPY = $(AVR_PREFIX)objcopy #OBJDUMP = $(AVR_PREFIX)objdump -USB_OBJS = usb.o +USB_OBJS = usb.o atu2.o OBJS = atusb.o board.o spi.o descr.o ep0.o $(USB_OBJS) vpath %.c usb/ diff --git a/atusb/fw3/ep0.c b/atusb/fw3/ep0.c index 10c920f..f7dafc1 100644 --- a/atusb/fw3/ep0.c +++ b/atusb/fw3/ep0.c @@ -57,7 +57,7 @@ static void do_buf_write(void *user) #define BUILD_OFFSET 7 /* '#' plus "65535" plus ' ' */ -static int my_setup(struct setup_request *setup) +static int my_setup(const struct setup_request *setup) { unsigned tmp; uint8_t i; diff --git a/atusb/fw3/usb/atu2.c b/atusb/fw3/usb/atu2.c new file mode 100644 index 0000000..ff1e767 --- /dev/null +++ b/atusb/fw3/usb/atu2.c @@ -0,0 +1,223 @@ +/* + * u/atu2.c - Chip-specific driver for Atmel ATxxxU2 USB chips + * + * 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 + +#define F_CPU 8000000UL +#include + +#include +#include "usb.h" +#include "../board.h" + + +#ifndef NULL +#define NULL 0 +#endif + +#if 1 +#define BUG_ON(cond) do { if (cond) panic(); } while (0) +#else +#define BUG_ON(cond) +#endif + + +#define NUM_EPS 1 + + +struct ep_descr eps[NUM_EPS]; + + +static uint16_t usb_read_word(void) +{ + uint8_t low; + + low = UEDATX; + return low | UEDATX << 8; +} + + +static void enable_addr(void *user) +{ + while (!(UEINTX & (1 << TXINI))); + UDADDR |= 1 << ADDEN; +} + + +int set_addr(uint8_t addr) +{ + UDADDR = addr; + usb_send(&eps[0], NULL, 0, enable_addr, NULL); + return 1; +} + + +static int ep_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(); + + if (!handle_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; + + UENUM = n; + if (UEINTX & (1 << RXSTPI)) { + /* @@@ EP_RX. EP_TX: cancel */ + if (!ep_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(); +} diff --git a/atusb/fw3/usb/usb.c b/atusb/fw3/usb/usb.c index 7585e8d..a908826 100644 --- a/atusb/fw3/usb/usb.c +++ b/atusb/fw3/usb/usb.c @@ -29,10 +29,6 @@ #include -#define F_CPU 8000000UL -#include - -#include #include "usb.h" #include "../board.h" @@ -50,17 +46,12 @@ extern void panic(void); #define BUG_ON(cond) #endif -struct ep_descr eps[5]; - -int (*user_setup)(struct setup_request *setup); +int (*user_setup)(const 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) { @@ -73,15 +64,6 @@ void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf, } -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; @@ -111,33 +93,9 @@ static int get_descriptor(uint8_t type, uint8_t index, uint16_t length) } -static void enable_addr(void *user) +int handle_setup(const struct setup_request *setup) { - 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) { + switch (setup->bmRequestType | setup->bRequest << 8) { /* * Device request @@ -146,7 +104,7 @@ static int handle_setup(void) */ case FROM_DEVICE(GET_STATUS): - if (setup.wLength != 2) + if (setup->wLength != 2) return 0; usb_send(&eps[0], "\000", 2, NULL, NULL); break; @@ -155,13 +113,11 @@ static int handle_setup(void) 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); + set_addr(setup->wValue); break; case FROM_DEVICE(GET_DESCRIPTOR): - if (!get_descriptor(setup.wValue >> 8, setup.wValue, - setup.wLength)) + if (!get_descriptor(setup->wValue >> 8, setup->wValue, + setup->wLength)) return 0; break; case TO_DEVICE(SET_DESCRIPTOR): @@ -170,7 +126,7 @@ static int handle_setup(void) usb_send(&eps[0], "", 1, NULL, NULL); break; case TO_DEVICE(SET_CONFIGURATION): - if (setup.wValue != config_descriptor[5]) + if (setup->wValue != config_descriptor[5]) return 0; break; @@ -191,8 +147,8 @@ static int handle_setup(void) const uint8_t *interface_descriptor = config_descriptor+9; - if (setup.wIndex != interface_descriptor[2] || - setup.wValue != interface_descriptor[3]) + if (setup->wIndex != interface_descriptor[2] || + setup->wValue != interface_descriptor[3]) return 0; } break; @@ -213,136 +169,8 @@ static int handle_setup(void) default: if (!user_setup) return 0; - if (!user_setup(&setup)) - return 0; + return user_setup(setup); } - 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; - - 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(); -} diff --git a/atusb/fw3/usb/usb.h b/atusb/fw3/usb/usb.h index a5fd92e..0453343 100644 --- a/atusb/fw3/usb/usb.h +++ b/atusb/fw3/usb/usb.h @@ -124,7 +124,7 @@ 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_setup)(const 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); @@ -139,7 +139,8 @@ extern void (*user_reset)(void); void usb_io(struct ep_descr *ep, enum ep_state state, uint8_t *buf, uint8_t size, void (*callback)(void *user), void *user); - +int handle_setup(const struct setup_request *setup); +int set_addr(uint8_t addr); void usb_init(void); void usb_poll(void);