Root/atusb/fw/usb/atu2.c

Source at commit 464ab40e3932a83b30626b99c4b658b4916fc24c created 4 years 8 months ago.
By Stefan Schmidt, Revert "atusb/fw/usb/: enable MCU reset on USB bus reset after config selection"
1/*
2 * fw/usb/atu2.c - Chip-specific driver for Atmel ATxxxU2 USB chips
3 *
4 * Written 2008-2011, 2013-2014 by Werner Almesberger
5 * Copyright 2008-2011, 2013-2014 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * Known issues:
15 * - no suspend/resume
16 * - we don't call back after failed transmissions,
17 * - we don't reset the EP buffer after failed receptions
18 * - enumeration often encounters an error -71 (from which it recovers)
19 */
20
21#include <stdbool.h>
22#include <stdint.h>
23
24#define F_CPU 8000000UL
25#include <util/delay.h>
26
27#include <avr/io.h>
28#include <avr/interrupt.h>
29#include "usb.h"
30#include "board.h"
31
32
33#ifndef NULL
34#define NULL 0
35#endif
36
37#if 1
38#define BUG_ON(cond) do { if (cond) panic(); } while (0)
39#else
40#define BUG_ON(cond)
41#endif
42
43
44struct ep_descr eps[NUM_EPS];
45
46
47static uint16_t usb_read_word(void)
48{
49    uint8_t low;
50
51    low = UEDATX;
52    return low | UEDATX << 8;
53}
54
55
56static void enable_addr(void *user)
57{
58    while (!(UEINTX & (1 << TXINI)));
59    UDADDR |= 1 << ADDEN;
60}
61
62
63void set_addr(uint8_t addr)
64{
65    UDADDR = addr;
66    usb_send(&eps[0], NULL, 0, enable_addr, NULL);
67}
68
69
70void usb_ep_change(struct ep_descr *ep)
71{
72    if (ep->state == EP_TX) {
73        UENUM = ep-eps;
74        UEIENX |= 1 << TXINE;
75    }
76}
77
78
79static bool ep_setup(void)
80{
81    struct setup_request setup;
82
83    BUG_ON(UEBCLX < 8);
84
85    setup.bmRequestType = UEDATX;
86    setup.bRequest = UEDATX;
87    setup.wValue = usb_read_word();
88    setup.wIndex = usb_read_word();
89    setup.wLength = usb_read_word();
90
91    if (!handle_setup(&setup))
92        return 0;
93    if (!(setup.bmRequestType & 0x80) && eps[0].state == EP_IDLE)
94        usb_send(&eps[0], NULL, 0, NULL, NULL);
95    return 1;
96}
97
98
99static bool ep_rx(struct ep_descr *ep)
100{
101    uint8_t size;
102
103    size = UEBCLX;
104    if (size > ep->end-ep->buf)
105        return 0;
106    while (size--)
107        *ep->buf++ = UEDATX;
108    if (ep->buf == ep->end) {
109        ep->state = EP_IDLE;
110        if (ep->callback)
111            ep->callback(ep->user);
112// if (ep == &eps[0])
113            usb_send(ep, NULL, 0, NULL, NULL);
114    }
115    return 1;
116}
117
118
119static void ep_tx(struct ep_descr *ep)
120{
121    uint8_t size = ep->end-ep->buf;
122    uint8_t left;
123
124    if (size > ep->size)
125        size = ep->size;
126    for (left = size; left; left--)
127        UEDATX = *ep->buf++;
128    if (size == ep->size)
129        return;
130    ep->state = EP_IDLE;
131}
132
133
134static void handle_ep(int n)
135{
136    struct ep_descr *ep = eps+n;
137    uint8_t mask;
138
139    UENUM = n;
140    if (UEINTX & (1 << RXSTPI)) {
141        /* @@@ EP_RX. EP_TX: cancel */
142        ep->state = EP_IDLE;
143        if (!ep_setup())
144            goto stall;
145        UEINTX = ~(1 << RXSTPI);
146    }
147    if (UEINTX & (1 << RXOUTI)) {
148        /* @@ EP_TX: cancel */
149        if (ep->state != EP_RX)
150            goto stall;
151        if (!ep_rx(ep))
152            goto stall;
153        /* @@@ gcc 4.5.2 wants this cast */
154        UEINTX = (uint8_t) ~(1 << RXOUTI | 1 << FIFOCON);
155    }
156    if (UEINTX & (1 << STALLEDI)) {
157        ep->state = EP_IDLE;
158        UEINTX = ~(1 << STALLEDI);
159    }
160    if (UEINTX & (1 << TXINI)) {
161        /* @@ EP_RX: cancel (?) */
162        if (ep->state == EP_TX) {
163            ep_tx(ep);
164            mask = 1 << TXINI;
165            if (n)
166                mask |= 1 << FIFOCON;
167            UEINTX = ~mask;
168            if (ep->state == EP_IDLE && ep->callback)
169                ep->callback(ep->user);
170        } else {
171            UEIENX &= ~(1 << TXINE);
172        }
173    }
174    return;
175
176stall:
177    UEINTX = ~(1 << RXSTPI | 1 << RXOUTI | 1 << STALLEDI);
178    ep->state = EP_IDLE;
179    UECONX |= 1 << STALLRQ;
180}
181
182
183static void ep_init(void)
184{
185    UENUM = 0;
186    UECONX = (1 << RSTDT) | (1 << EPEN); /* enable */
187    UECFG0X = 0; /* control, direction is ignored */
188    UECFG1X = 3 << EPSIZE0; /* 64 bytes */
189    UECFG1X |= 1 << ALLOC;
190
191    while (!(UESTA0X & (1 << CFGOK)));
192
193    UEIENX =
194        (1 << RXSTPE) | (1 << RXOUTE) | (1 << STALLEDE) | (1 << TXINE);
195
196    eps[0].state = EP_IDLE;
197    eps[0].size = 64;
198
199#ifndef BOOT_LOADER
200
201    UENUM = 1;
202    UECONX = (1 << RSTDT) | (1 << EPEN); /* enable */
203    UECFG0X = (1 << EPTYPE1) | (1 << EPDIR); /* bulk IN */
204    UECFG1X = 3 << EPSIZE0; /* 64 bytes */
205    UECFG1X |= 1 << ALLOC;
206
207    while (!(UESTA0X & (1 << CFGOK)));
208
209    UEIENX = (1 << STALLEDE) | (1 << TXINE);
210
211    eps[1].state = EP_IDLE;
212    eps[1].size = 64;
213
214#endif
215}
216
217
218ISR(USB_GEN_vect)
219{
220    uint8_t flags;
221
222    flags = UDINT;
223    if (flags & (1 << EORSTI)) {
224        if (user_reset)
225            user_reset();
226        ep_init();
227        UDINT = ~(1 << EORSTI);
228    }
229}
230
231
232ISR(USB_COM_vect)
233{
234    uint8_t flags, i;
235
236    flags = UEINT;
237    for (i = 0; i != NUM_EPS; i++)
238        if (flags & (1 << i))
239            handle_ep(i);
240}
241
242
243void usb_reset(void)
244{
245    UDCON |= 1 << DETACH; /* detach the pull-up */
246    _delay_ms(1);
247}
248
249
250void usb_init(void)
251{
252    USBCON |= 1 << FRZCLK; /* freeze the clock */
253
254    /* enable the PLL and wait for it to lock */
255    PLLCSR &= ~(1 << PLLP2 | 1 << PLLP1 | 1 << PLLP0);
256    PLLCSR |= 1 << PLLE;
257    while (!(PLLCSR & (1 << PLOCK)));
258
259    USBCON &= ~(1 << USBE); /* reset the controller */
260    USBCON |= 1 << USBE;
261
262    USBCON &= ~(1 << FRZCLK); /* thaw the clock */
263
264    UDCON &= ~(1 << DETACH); /* attach the pull-up */
265    UDIEN = 1 << EORSTE; /* enable device interrupts */
266// UDCON |= 1 << RSTCPU; /* reset CPU on bus reset */
267
268    ep_init();
269}
270

Archive Download this file



interactive